zorba-coders team mailing list archive
-
zorba-coders team
-
Mailing list archive
-
Message #27019
[Merge] lp:~zorba-coders/zorba/feature-setvar-typed--email into lp:zorba
Paul J. Lucas has proposed merging lp:~zorba-coders/zorba/feature-setvar-typed--email into lp:zorba.
Commit message:
Fixed #include.
Requested reviews:
Paul J. Lucas (paul-lucas)
For more details, see:
https://code.launchpad.net/~zorba-coders/zorba/feature-setvar-typed--email/+merge/217844
Fixed #include.
--
https://code.launchpad.net/~zorba-coders/zorba/feature-setvar-typed--email/+merge/217844
Your team Zorba Coders is subscribed to branch lp:zorba.
=== added file 'CMakeLists.txt'
--- CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ CMakeLists.txt 2014-04-30 23:07:12 +0000
@@ -0,0 +1,29 @@
+# Copyright 2006-2010 The FLWOR Foundation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+CMAKE_MINIMUM_REQUIRED (VERSION 2.6)
+
+PROJECT (zorba_email_module)
+ENABLE_TESTING ()
+INCLUDE (CTest)
+
+FIND_PACKAGE (Zorba REQUIRED HINTS "${ZORBA_BUILD_DIR}")
+INCLUDE ("${Zorba_USE_FILE}")
+
+SET_CMAKE_MODULE_PATH()
+
+ADD_TEST_DIRECTORY ("${PROJECT_SOURCE_DIR}/test")
+ADD_SUBDIRECTORY ("src")
+
+DONE_DECLARING_ZORBA_URIS ()
=== renamed file 'CMakeLists.txt' => 'CMakeLists.txt.moved'
=== added directory 'cmake_modules'
=== renamed directory 'cmake_modules' => 'cmake_modules.moved'
=== added file 'cmake_modules/FindCClient.cmake'
--- cmake_modules/FindCClient.cmake 1970-01-01 00:00:00 +0000
+++ cmake_modules/FindCClient.cmake 2014-04-30 23:07:12 +0000
@@ -0,0 +1,80 @@
+# Copyright 2006-2008 The FLWOR Foundation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# - Find the C-CLIENT library that is part of the UW IMAP toolkit
+#
+# Once done this will define
+#
+# CCLIENT_FOUND - True if C-CLIENT library found.
+# CCLIENT_INCLUDE_DIRS - Directory to include to get C-CLIENT headers
+# CCLIENT_LIBRARIES - Libraries to link against for the C-CLIENT library
+#
+
+IF(CCLIENT_INCLUDE_DIRS AND CCLIENT_LIBRARIES)
+ # Already in cache, be silent
+ SET(CCLIENT_FIND_QUIETLY TRUE)
+ENDIF(CCLIENT_INCLUDE_DIRS AND CCLIENT_LIBRARIES)
+
+# Look for the headers.
+FIND_PATH(
+ CCLIENT_INCLUDE
+ NAMES c-client.h c-client/c-client.h
+ PATHS ${CCLIENT_INCLUDE_DIR} /usr/include/imap /usr/include/c-client /usr/local/include/c-client /opt/local/include/c-client
+ DOC "Include directory for the CCLient library headers (the path to 'c-client.h' file)")
+
+IF(CCLIENT_INCLUDE)
+ IF(WIN32)
+ IF(EXISTS "${CCLIENT_INCLUDE}/c-client/c-client.h")
+ SET(CCLIENT_INCLUDE "${CCLIENT_INCLUDE}/c-client" CACHE PATH "Path to a file." FORCE)
+ ENDIF(EXISTS "${CCLIENT_INCLUDE}/c-client/c-client.h")
+ ENDIF(WIN32)
+ MESSAGE(STATUS "Found CCLIENT include directory -- " ${CCLIENT_INCLUDE})
+ELSE(CCLIENT_INCLUDE)
+ MESSAGE(STATUS "Could not find CCLIENT include directory")
+ENDIF(CCLIENT_INCLUDE)
+
+# only for GUI purposes
+MARK_AS_ADVANCED(CCLIENT_INCLUDE)
+
+# Look for the library.
+FIND_LIBRARY(
+ CCLIENT_LIBRARY
+ NAMES c-client.a libc-client.a c-client libc-client4.a c-client4 cclient.lib c-client/libc-client.a c-client/cclient.lib c-client/Release/cclient.lib
+ PATHS ${CCLIENT_LIBRARY_DIR} /usr/local/lib /opt/local/lib /usr/lib /usr/lib/c-client
+ DOC "Library to link against for the email support (c-client, libc-client or cclient.lib)")
+
+IF(CCLIENT_LIBRARY)
+ MESSAGE(STATUS "Found CCLIENT library -- " ${CCLIENT_LIBRARY})
+ELSE(CCLIENT_LIBRARY)
+ MESSAGE(STATUS "Could not find CCLIENT library")
+ENDIF(CCLIENT_LIBRARY)
+
+# Copy the results to the output variables.
+IF(CCLIENT_INCLUDE AND CCLIENT_LIBRARY)
+ SET(CCLIENT_FOUND 1)
+ SET(CCLIENT_LIBRARIES ${CCLIENT_LIBRARY})
+ SET(CCLIENT_INCLUDE_DIRS ${CCLIENT_INCLUDE})
+
+ # Do not treat the operator name keywords and, bitand, bitor, compl, not, or and xor
+ # as synonyms as keywords. Needed in order to include C-CLIENT library
+ IF(CMAKE_COMPILER_IS_GNUCXX)
+ IF(NOT CMAKE_CXX_FLAGS MATCHES "-fno-operator-names")
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-operator-names")
+ ENDIF(NOT CMAKE_CXX_FLAGS MATCHES "-fno-operator-names")
+ ENDIF(CMAKE_COMPILER_IS_GNUCXX)
+ELSE(CCLIENT_INCLUDE AND CCLIENT_LIBRARY)
+ SET(CCLIENT_FOUND 0)
+ SET(CCLIENT_LIBRARIES)
+ SET(CCLIENT_INCLUDE_DIRS)
+ENDIF(CCLIENT_INCLUDE AND CCLIENT_LIBRARY)
=== added file 'cmake_modules/FindKerberos.cmake'
--- cmake_modules/FindKerberos.cmake 1970-01-01 00:00:00 +0000
+++ cmake_modules/FindKerberos.cmake 2014-04-30 23:07:12 +0000
@@ -0,0 +1,47 @@
+# Copyright 2006-2008 The FLWOR Foundation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Finds the KERBEROS library
+#
+# KERBEROS_FOUND - True if SASL library found.
+# KERBEROS_LIBRARY - Libraries to link against for the SASL library
+#
+
+if (KERBEROS_LIBRARIES)
+ # Already in cache, be silent
+ set(KERBEROS_FIND_QUIETLY TRUE)
+endif (KERBEROS_LIBRARIES)
+
+# Look for the library.
+find_library(
+ KERBEROS_LIBRARY
+ NAMES gssapi_krb5
+ PATHS ${KERBEROS_LIBRARY_DIRS} /opt/local/lib /usr/lib /usr/local/lib
+ DOC "Library to link against for kerberos support (gssapi_krb5)")
+mark_as_advanced(KERBEROS_LIBRARY)
+
+if (KERBEROS_LIBRARY)
+ MESSAGE(STATUS "Found Kerberos library -- " ${KERBEROS_LIBRARY})
+else (KERBEROS_LIBRARY)
+ MESSAGE(STATUS "Could not find Kerberos library")
+endif (KERBEROS_LIBRARY)
+
+# Copy the results to the output variables.
+if(KERBEROS_LIBRARY)
+ set(KERBEROS_FOUND 1)
+else(KERBEROS_LIBRARY)
+ set(KERBEROS_FOUND 0)
+ set(KERBEROS_LIBRARY)
+ set(KERBEROS_INCLUDE)
+endif(KERBEROS_LIBRARY)
=== added file 'cmake_modules/FindPAM.cmake'
--- cmake_modules/FindPAM.cmake 1970-01-01 00:00:00 +0000
+++ cmake_modules/FindPAM.cmake 2014-04-30 23:07:12 +0000
@@ -0,0 +1,37 @@
+# Copyright 2006-2008 The FLWOR Foundation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Try to find the PAM libraries
+#
+# PAM_FOUND - True if PAM library found
+# PAM_INCLUDE_DIR - Directory to include to get PAM headers
+# PAM_LIBRARIES - Libraries to link against for the PAM library
+
+if (PAM_INCLUDE_DIR AND PAM_LIBRARY)
+ # Already in cache, be silent
+ set(PAM_FIND_QUIETLY TRUE)
+endif (PAM_INCLUDE_DIR AND PAM_LIBRARY)
+
+find_path(PAM_INCLUDE_DIR NAMES security/pam_appl.h pam/pam_appl.h)
+find_library(PAM_LIBRARY pam)
+find_library(DL_LIBRARY dl)
+
+if (PAM_INCLUDE_DIR AND PAM_LIBRARY)
+ set(PAM_FOUND TRUE)
+ if (DL_LIBRARY)
+ set(PAM_LIBRARIES ${PAM_LIBRARY} ${DL_LIBRARY})
+ else (DL_LIBRARY)
+ set(PAM_LIBRARIES ${PAM_LIBRARY})
+ endif (DL_LIBRARY)
+endif (PAM_INCLUDE_DIR AND PAM_LIBRARY)
=== added directory 'cmake_modules/Windows'
=== added file 'cmake_modules/Windows/FindCClient.cmake'
--- cmake_modules/Windows/FindCClient.cmake 1970-01-01 00:00:00 +0000
+++ cmake_modules/Windows/FindCClient.cmake 2014-04-30 23:07:12 +0000
@@ -0,0 +1,34 @@
+# Copyright 2010 The FLWOR Foundation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# - Find the C-CLIENT library that is part of the UW IMAP toolkit on Windows
+#
+# This is a proxy module that calls the FindCClient.cmake module. Before
+# doing that, we try to guess where CClient might be on the user's machine.
+# The user should provide ZORBA_THIRD_PARTY_REQUIREMENTS which is a path where
+# the CClient directory can be found. The CClient directory must have "imap"
+# (case insensitive) in its name.
+#
+# This module helps the Windows user to avoid providing the following two
+# variables when building Zorba:
+# -D CCLIENT_INCLUDE="path_to_3rd_party_dir\*imap*\c-client"
+# -D CCLIENT_LIBRARY="path_to_3rd_party_dir\*imap*\c-client\Release\cclient.lib"
+#
+# See the FindCClient.cmake module shipped with Zorba for more information.
+
+FIND_PACKAGE_WIN32 (
+ NAME "CClient"
+ FOUND_VAR "CCLIENT_FOUND"
+ SEARCH_NAMES "imap;cclient;c-client"
+)
=== added directory 'examples'
=== added directory 'examples/Queries'
=== added directory 'examples/Queries/imap'
=== added file 'examples/Queries/imap/copy_example.xq'
--- examples/Queries/imap/copy_example.xq 1970-01-01 00:00:00 +0000
+++ examples/Queries/imap/copy_example.xq 2014-04-30 23:07:12 +0000
@@ -0,0 +1,23 @@
+(:
+ : This example shows how to use the copy function of the http://www.zorba-xquery.com/modules/email/imap module.
+ :
+ : First we search for a message with the word copy in the subject. When we have found this message, we
+ : use the copy function to copy it internally to the CopyFolder folder.
+ : This creates a new message in the copy folder with a own unique identifier and message sequence number.
+ :)
+
+import module namespace imap = 'http://www.zorba-xquery.com/modules/email/imap';
+
+
+(: This variable contains the information of the account on the IMAP server. :)
+let $hostInfo :=
+ <hostInfo xmlns="http://www.zorba-xquery.com/modules/email";>
+ <hostName>mail.28msec.com/novalidate-cert</hostName>
+ <userName>imaptest</userName>
+ <password>cclient</password>
+ </hostInfo>
+
+let $uids := imap:search($hostInfo, "INBOX", "SUBJECT copy2", true())
+
+return
+ imap:copy($hostInfo, "INBOX", "INBOX.CopyFolder", $uids, true())
=== added file 'examples/Queries/imap/create_rename_delete_example.xq'
--- examples/Queries/imap/create_rename_delete_example.xq 1970-01-01 00:00:00 +0000
+++ examples/Queries/imap/create_rename_delete_example.xq 2014-04-30 23:07:12 +0000
@@ -0,0 +1,36 @@
+(:
+ : This example shows how to use the create, delete function of the
+ : http://www.zorba-xquery.com/modules/email/imap module.
+ :
+ : Using the host information stored in the variable $hostInfo a new mailbox
+ : is created on the mail.28msec.com server for this account.
+ :
+ : The mailbox name is partly random (to make sure that there is no other
+ : mailbox with that name). Then, we rename the mailbox to another random
+ : generated name. In the end the renamed mailbox is deleted to make sure that
+ : the account does not get swamped with useless mailboxes.
+ :
+ : If no error is thrown, all operations were successful.
+ :)
+
+import module namespace imap = 'http://www.zorba-xquery.com/modules/email/imap';
+import module namespace random = 'http://www.zorba-xquery.com/modules/random';
+
+
+(: This variable contains the information of the account on the IMAP server. :)
+let $hostInfo :=
+ <hostInfo xmlns="http://www.zorba-xquery.com/modules/email";>
+ <hostName>mail.28msec.com/novalidate-cert</hostName>
+ <userName>imaptest</userName>
+ <password>cclient</password>
+ </hostInfo>
+
+let $mailboxName := fn:concat("INBOX.", fn:substring(random:uuid(), 0, 4))
+let $newMailboxName := fn:concat("INBOX.", fn:substring(random:uuid(), 0, 5))
+
+return
+ {
+ imap:create($hostInfo, $mailboxName);
+ imap:rename($hostInfo, $mailboxName, $newMailboxName);
+ imap:delete($hostInfo, $newMailboxName)
+ }
=== added file 'examples/Queries/imap/expunge_example.xq'
--- examples/Queries/imap/expunge_example.xq 1970-01-01 00:00:00 +0000
+++ examples/Queries/imap/expunge_example.xq 2014-04-30 23:07:12 +0000
@@ -0,0 +1,69 @@
+(:
+ : This example shows how to use the expunge function of the http://www.zorba-xquery.com/modules/email/imap module.
+ : Using the host information stored in the variable $hostInfo first the search function is used to get
+ : the unique id of the all messages with the word delete in its subject.
+ : Then the delete flag is set on these messages using the set-flags method of the imap-module.
+ : The call to expunge on the mailbox then deletes all messages that have the delete flag set.
+ :
+ : This example is concluded by using the send function to send a new mail to the inbox to make sure that
+ : there will be a message to delete next time the example is used.
+ :)
+
+import module namespace imap = 'http://www.zorba-xquery.com/modules/email/imap';
+import module namespace smtp = 'http://www.zorba-xquery.com/modules/email/smtp';
+
+
+(: This variable contains the information of the account on the IMAP server. :)
+let $hostInfo :=
+ <hostInfo xmlns="http://www.zorba-xquery.com/modules/email";>
+ <hostName>mail.28msec.com/novalidate-cert</hostName>
+ <userName>imaptest</userName>
+ <password>cclient</password>
+ </hostInfo>
+
+(: This variable contains the information of the account from which the email should be sent. :)
+let $senderHostInfo :=
+ <hostInfo xmlns="http://www.zorba-xquery.com/modules/email";>
+ <hostName>smtp.gmail.com:587/tls/novalidate-cert</hostName>
+ <userName>zorba.smtp.sender</userName>
+ <password>1openssl!</password>
+ </hostInfo>
+
+(: the XML representation of the email to be sent, as described by the XML schema
+ http://www.zorba-xquery.com/modules/email :)
+let $email :=
+ <message xmlns="http://www.zorba-xquery.com/modules/email";>
+ <envelope>
+ <date>2010-11-26T15:50:39-04:01</date>
+ <subject>delete</subject>
+ <recipient>
+ <to>
+ <name>Test Account</name>
+ <email>imaptest@xxxxxxxxxx</email>
+ </to>
+ </recipient>
+ </envelope>
+ <body>
+ <content contentType="text/plain" charset="UTF-8" contentTransferEncoding="ENC8BIT">
+ Oh yeah
+ </content>
+ </body>
+ </message>
+
+let $flags :=
+ <flags xmlns="http://www.zorba-xquery.com/modules/email";>
+ <deleted/>
+ </flags>
+
+let $ids := imap:search($hostInfo, "INBOX", "SUBJECT delete", true())
+return {
+ for $id in $ids
+ return
+ imap:set-flags($hostInfo, "INBOX", $id, $flags, true());
+
+ (: expunge from server :)
+ imap:expunge($hostInfo, "INBOX");
+
+ (: resend a "delete" message to have it next time when we execute this example :)
+ smtp:send($senderHostInfo, $email);
+}
=== added file 'examples/Queries/imap/fetch_envelope_example.xq'
--- examples/Queries/imap/fetch_envelope_example.xq 1970-01-01 00:00:00 +0000
+++ examples/Queries/imap/fetch_envelope_example.xq 2014-04-30 23:07:12 +0000
@@ -0,0 +1,51 @@
+(:
+ : This example shows how to use the fetch-envelope function of
+ : the http://www.zorba-xquery.com/modules/email/imap module.
+ :
+ : Using the host information stored in the variable $hostInfo, first a message
+ : containing the word "test" in the subject is searched for, using the search
+ : function. Then, the envelope of the first message found is fetched.
+ :
+ : The XML output of this script should look something like:
+ :
+ : <envelope xmlns="http://www.zorba-xquery.com/modules/email";>
+ : <date>2011-02-14T13:07:38</date>
+ : <from>
+ : <name>Daniel Thomas</name>
+ : <email>thomas.daniel.james@xxxxxxxxx</email>
+ : </from>
+ : <sender>
+ : <name>Daniel Thomas</name>
+ : <email>thomas.daniel.james@xxxxxxxxx</email>
+ : </sender>
+ : <replyTo>
+ : <name>Daniel Thomas</name>
+ : <email>thomas.daniel.james@xxxxxxxxx</email>
+ : </replyTo>
+ : <subject>test</subject>
+ : <recipient>
+ : <to>
+ : <email>imaptest@xxxxxxxxxx</email>
+ : </to>
+ : </recipient>
+ : <messageId><AANLkTinSujfq9-UgGDvX+RcOrhvQf5JTnTdwSLNTiqZ5@xxxxxxxxxxxxxx></messageId>
+ : <flags/>
+ : </envelope>
+ :
+ : If no error is thrown, all operations were successful.
+ :)
+
+import module namespace imap = 'http://www.zorba-xquery.com/modules/email/imap';
+
+
+(: This variable contains the information of the account on the IMAP server. :)
+let $hostInfo :=
+ <hostInfo xmlns="http://www.zorba-xquery.com/modules/email";>
+ <hostName>mail.28msec.com/novalidate-cert</hostName>
+ <userName>imaptest</userName>
+ <password>cclient</password>
+ </hostInfo>
+
+let $uids := imap:search($hostInfo, "INBOX", "SUBJECT test", false())
+return
+ imap:fetch-envelope($hostInfo, "INBOX", $uids[1], false())
=== added file 'examples/Queries/imap/fetch_flags_example.xq'
--- examples/Queries/imap/fetch_flags_example.xq 1970-01-01 00:00:00 +0000
+++ examples/Queries/imap/fetch_flags_example.xq 2014-04-30 23:07:12 +0000
@@ -0,0 +1,33 @@
+(:
+ : This example shows how to use the fetch-flags function of the
+ : http://www.zorba-xquery.com/modules/email/imap module.
+ :
+ : First, the unique identifiers of all messages containing the word "flags" in
+ : the subject are retrieved. Then, the flags of the first message found is
+ : fetched.
+ :
+ : The resulting XML should look something like this:
+ :
+ : <flags xmlns="http://www.zorba-xquery.com/modules/email";>
+ : <seen/>
+ : <answered/>
+ : </flags>
+ :
+ : If no error is thrown, all operations were successful.
+ :)
+
+import module namespace imap = 'http://www.zorba-xquery.com/modules/email/imap';
+
+
+(: This variable contains the information of the account on the IMAP server. :)
+let $hostInfo :=
+ <hostInfo xmlns="http://www.zorba-xquery.com/modules/email";>
+ <hostName>mail.28msec.com/novalidate-cert</hostName>
+ <userName>imaptest</userName>
+ <password>cclient</password>
+ </hostInfo>
+
+let $uids := imap:search($hostInfo, "INBOX", "SUBJECT flags", true())
+
+return
+ imap:fetch-flags($hostInfo, "INBOX", $uids[1], true())
=== added file 'examples/Queries/imap/fetch_from_example.xq'
--- examples/Queries/imap/fetch_from_example.xq 1970-01-01 00:00:00 +0000
+++ examples/Queries/imap/fetch_from_example.xq 2014-04-30 23:07:12 +0000
@@ -0,0 +1,27 @@
+(:
+ : This example shows how to use the fetch-from function of the
+ : http://www.zorba-xquery.com/modules/email/imap module.
+ :
+ : First, the sequence numbers of all messages containing the word "flags" in
+ : the subject are retrieved. Then, the from field of the first message found
+ : is fetched. This contains the name and the email address of the sender.
+ :
+ : If no error is thrown, all operations were successful.
+ :)
+
+import module namespace imap = 'http://www.zorba-xquery.com/modules/email/imap';
+
+
+(: This variable contains the information of the account on the IMAP server. :)
+let $hostInfo :=
+ <hostInfo xmlns="http://www.zorba-xquery.com/modules/email";>
+ <hostName>mail.28msec.com/novalidate-cert</hostName>
+ <userName>imaptest</userName>
+ <password>cclient</password>
+ </hostInfo>
+
+
+let $uids := imap:search($hostInfo, "INBOX", "SUBJECT flags", false())
+
+return
+ imap:fetch-from($hostInfo, "INBOX", $uids[1])
=== added file 'examples/Queries/imap/fetch_message_example.xq'
--- examples/Queries/imap/fetch_message_example.xq 1970-01-01 00:00:00 +0000
+++ examples/Queries/imap/fetch_message_example.xq 2014-04-30 23:07:12 +0000
@@ -0,0 +1,46 @@
+(:
+ : This example shows how to use the fetch-message function of the
+ : http://www.zorba-xquery.com/modules/email/imap module.
+ :
+ : First, the sequence numbers of all messages containing the word "test" in
+ : the subject are retrieved. Then, the first message found is fetched.
+ :
+ : The resulting XML should look something like this:
+ :
+ : <message xmlns="http://www.zorba-xquery.com/modules/email";>
+ : <envelope>
+ : <date>2011-02-14T13:07:38</date>
+ : <from><name>Daniel Thomas</name><email>thomas.daniel.james@xxxxxxxxx</email></from>
+ : <sender><name>Daniel Thomas</name><email>thomas.daniel.james@xxxxxxxxx</email></sender>
+ : <replyTo><name>Daniel Thomas</name><email>thomas.daniel.james@xxxxxxxxx</email></replyTo>
+ : <subject>test</subject><recipient><to><email>imaptest@xxxxxxxxxx</email></to></recipient>
+ : <messageId><AANLkTinSujfq9-UgGDvX+RcOrhvQf5JTnTdwSLNTiqZ5@xxxxxxxxxxxxxx></messageId>
+ : <flags/>
+ : </envelope>
+ : <mimeVersion>1.0</mimeVersion>
+ : <body>
+ : <multipart contentType="multipart/alternative" charset="us-ascii" contentTransferEncoding="ENC7BIT">
+ : <content contentType="text/plain" charset="us-ascii" contentTransferEncoding="ENC8BIT">This is a test message
</content>
+ : <content contentType="text/html" charset="us-ascii" contentTransferEncoding="ENC8BIT">This is a test message
</content>
+ : </multipart>
+ : </body>
+ : </message>
+ :
+ : If no error is thrown, all operations were successful.
+ :)
+
+import module namespace imap = 'http://www.zorba-xquery.com/modules/email/imap';
+
+
+(: This variable contains the information of the account on the IMAP server. :)
+let $hostInfo :=
+ <hostInfo xmlns="http://www.zorba-xquery.com/modules/email";>
+ <hostName>mail.28msec.com/novalidate-cert</hostName>
+ <userName>imaptest</userName>
+ <password>cclient</password>
+ </hostInfo>
+
+let $uids := imap:search($hostInfo, "INBOX", "SUBJECT test", false())
+
+return
+ imap:fetch-message($hostInfo, "INBOX", $uids[1], false())
=== added file 'examples/Queries/imap/fetch_message_sequence_number_example.xq'
--- examples/Queries/imap/fetch_message_sequence_number_example.xq 1970-01-01 00:00:00 +0000
+++ examples/Queries/imap/fetch_message_sequence_number_example.xq 2014-04-30 23:07:12 +0000
@@ -0,0 +1,26 @@
+(:
+ : This example shows how to use the fetch-message-sequence-number function of
+ : the http://www.zorba-xquery.com/modules/email/imap module.
+ :
+ : First, the unique identifiers of all messages containing the word "flags" in
+ : the subject are retrieved. Then, the message sequence number of the first
+ : message found is fetched.
+ :
+ : If no error is thrown, all operations were successful.
+ :)
+
+import module namespace imap = 'http://www.zorba-xquery.com/modules/email/imap';
+
+
+(: This variable contains the information of the account on the IMAP server. :)
+let $hostInfo :=
+ <hostInfo xmlns="http://www.zorba-xquery.com/modules/email";>
+ <hostName>mail.28msec.com/novalidate-cert</hostName>
+ <userName>imaptest</userName>
+ <password>cclient</password>
+ </hostInfo>
+
+let $sequenceNumbers := imap:search($hostInfo, "INBOX", "SUBJECT flags", true())
+
+return
+ imap:fetch-message-sequence-number($hostInfo, "INBOX", $sequenceNumbers[1])
=== added file 'examples/Queries/imap/fetch_subject_example.xq'
--- examples/Queries/imap/fetch_subject_example.xq 1970-01-01 00:00:00 +0000
+++ examples/Queries/imap/fetch_subject_example.xq 2014-04-30 23:07:12 +0000
@@ -0,0 +1,27 @@
+(:
+ : This example shows how to use the fetch-subject function of
+ : the http://www.zorba-xquery.com/modules/email/imap module.
+ :
+ : First, the message sequences number of all messages containing the word flags
+ : in the subject are retrieved. Then, the subject of the message found is
+ : fetched.
+ :
+ : If no error is thrown, all operations were successful.
+ :)
+
+import module namespace imap = 'http://www.zorba-xquery.com/modules/email/imap';
+
+
+(: This variable contains the information of the account on the IMAP server. :)
+let $hostInfo :=
+ <hostInfo xmlns="http://www.zorba-xquery.com/modules/email";>
+ <hostName>mail.28msec.com/novalidate-cert</hostName>
+ <userName>imaptest</userName>
+ <password>cclient</password>
+ </hostInfo>
+
+
+let $uids := imap:search($hostInfo, "INBOX", "SUBJECT flags", false())
+
+return
+ imap:fetch-subject($hostInfo, "INBOX", $uids[1])
=== added file 'examples/Queries/imap/fetch_uid_example.xq'
--- examples/Queries/imap/fetch_uid_example.xq 1970-01-01 00:00:00 +0000
+++ examples/Queries/imap/fetch_uid_example.xq 2014-04-30 23:07:12 +0000
@@ -0,0 +1,26 @@
+(:
+ : This example shows how to use the fetch-uid function of the
+ : http://www.zorba-xquery.com/modules/email/imap module.
+ :
+ : First, the message sequence numbers of all messages with the word "flags" in
+ : the subject are retrieved. Then, the unique identifier of the first message
+ : foundis fetched.
+ :
+ : If no error is thrown, all operations were successful.
+ :)
+
+import module namespace imap = 'http://www.zorba-xquery.com/modules/email/imap';
+
+
+(: This variable contains the information of the account on the IMAP server. :)
+let $hostInfo :=
+ <hostInfo xmlns="http://www.zorba-xquery.com/modules/email";>
+ <hostName>mail.28msec.com/novalidate-cert</hostName>
+ <userName>imaptest</userName>
+ <password>cclient</password>
+ </hostInfo>
+
+let $uids := imap:search($hostInfo, "INBOX", "SUBJECT flags", false())
+
+return
+ imap:fetch-uid($hostInfo, "INBOX", $uids[1])
=== added file 'examples/Queries/imap/list_example.xq'
--- examples/Queries/imap/list_example.xq 1970-01-01 00:00:00 +0000
+++ examples/Queries/imap/list_example.xq 2014-04-30 23:07:12 +0000
@@ -0,0 +1,38 @@
+(:
+ : This example shows how to use the list function of the
+ : http://www.zorba-xquery.com/modules/email/imap module.
+ :
+ : Using the host information stored in the variable $hostInfo, all folders on
+ : the given account that match the pattern "INBOX.Dr*" are listed.
+ :
+ : The resulting XML should look something like this:
+ :
+ : <mailbox xmlns="http://www.zorba-xquery.com/modules/email";>
+ : <hostName/>
+ : <mailboxName>INBOX.Drafts</mailboxName>
+ : </mailbox>
+ :
+ : The parameters for the list function are interesting. The second parameter
+ : is applied to the pattern in an implementation dependent fashion to search
+ : for matching mailbox names. At this point we haven't found an example where
+ : this could be useful or even usable, so you could pass the empty string.
+ :
+ : The fourth and last parameter lets you choose if only subscribed mailboxes
+ : should be considered for the search.
+ :
+ : If no error is thrown, all operations were successful.
+ :)
+
+import module namespace imap = 'http://www.zorba-xquery.com/modules/email/imap';
+
+
+(: This variable contains the information of the account on the IMAP server. :)
+let $hostInfo :=
+ <hostInfo xmlns="http://www.zorba-xquery.com/modules/email";>
+ <hostName>mail.28msec.com/novalidate-cert</hostName>
+ <userName>imaptest</userName>
+ <password>cclient</password>
+ </hostInfo>
+
+return
+ imap:list($hostInfo, "", "INBOX.Dra*", false())
=== added file 'examples/Queries/imap/mimetypes_example.xq'
--- examples/Queries/imap/mimetypes_example.xq 1970-01-01 00:00:00 +0000
+++ examples/Queries/imap/mimetypes_example.xq 2014-04-30 23:07:12 +0000
@@ -0,0 +1,44 @@
+(:
+ : This should issue 4
+ :)
+
+import schema namespace email = 'http://www.zorba-xquery.com/modules/email';
+
+let $messages :=
+ for $type in ("application/3gpp-ims+xml","application/cals-1840","application/pkcs7-signature","application/vnd.openxmlformats-officedocument.presentationml.comments+xml")
+ return
+ fn:validate {
+ <email:message xmlns:email="http://www.zorba-xquery.com/modules/email/email";>
+ <envelope>
+ <date>2010-11-26T15:50:39</date>
+ <from>
+ <email>zorba.smtp.sender@xxxxxxxxx</email>
+ </from>
+ <sender>
+ <email>zorba.smtp.sender@xxxxxxxxx</email>
+ </sender>
+ <replyTo>
+ <email>zorba.smtp.sender@xxxxxxxxx</email>
+ </replyTo>
+ <subject>RegexTest</subject>
+ <recipient>
+ <to>
+ <email>imaptest@xxxxxxxxxx</email>
+ </to>
+ </recipient>
+ <messageId><4ea85e91.679e440a.0f97.241e@xxxxxxxxxxxxx></messageId>
+ <flags>
+ <seen/>
+ </flags>
+ </envelope>
+ <mimeVersion>1.0</mimeVersion>
+ <body>
+ <multipart contentType="multipart/mixed" charset="us-ascii" contentTransferEncoding="ENC7BIT">
+ <content contentType="text/plain" charset="us-ascii" contentTransferEncoding="ENCQUOTEDPRINTABLE">=0A Zorba really rocks. =0A </content>
+ <content contentType="{$type}" charset="us-ascii" contentTransferEncoding="ENCBASE64" contentDisposition="the-truth.gif">some content</content>
+ </multipart>
+ </body>
+ </email:message>
+ }
+return
+ fn:count($messages)
=== added file 'examples/Queries/imap/move_example.xq'
--- examples/Queries/imap/move_example.xq 1970-01-01 00:00:00 +0000
+++ examples/Queries/imap/move_example.xq 2014-04-30 23:07:12 +0000
@@ -0,0 +1,30 @@
+(:
+ : This example shows how to use the move function of the
+ : http://www.zorba-xquery.com/modules/email/imap module.
+ :
+ : First, we search in the "INBOX.MoveFolder" mailbox for messages containing
+ : the word "move" in the subject. If such messages are found, they are moved
+ : to the INBOX. If not messages were found in the "INBOX.MoveFolder" mailbox,
+ : the move is performed inthe other direction.
+ :)
+
+import module namespace imap = 'http://www.zorba-xquery.com/modules/email/imap';
+
+
+(: This variable contains the information of the account on the IMAP server. :)
+let $hostInfo :=
+ <hostInfo xmlns="http://www.zorba-xquery.com/modules/email";>
+ <hostName>mail.28msec.com/novalidate-cert</hostName>
+ <userName>imaptest</userName>
+ <password>cclient</password>
+ </hostInfo>
+
+let $uids := imap:search($hostInfo, "INBOX.MoveFolder", "SUBJECT move", true())
+
+return
+ if ($uids) then
+ imap:move($hostInfo, "INBOX.MoveFolder", "INBOX", $uids, true());
+ else
+ let $uids := imap:search($hostInfo, "INBOX", "SUBJECT move", true())
+ return
+ imap:move($hostInfo, "INBOX", "INBOX.MoveFolder", $uids, true())
=== added file 'examples/Queries/imap/search_example.xq'
--- examples/Queries/imap/search_example.xq 1970-01-01 00:00:00 +0000
+++ examples/Queries/imap/search_example.xq 2014-04-30 23:07:12 +0000
@@ -0,0 +1,27 @@
+(:
+ : This example shows how to use the search function of the
+ : http://www.zorba-xquery.com/modules/email/imap module.
+ :
+ : The mailbox INBOX of the user described by the $hostInfo variable is
+ : searched for messages containing the word "test" in their subject.
+ :
+ : The search function returns the sequence of unique identifiers of mesages
+ : that comply with the search criteria. By setting the last argument to
+ : fn:false(), the message sequence numbers are returned instead.
+ :
+ : If no error is thrown, all operations were successful.
+ :)
+
+import module namespace imap = 'http://www.zorba-xquery.com/modules/email/imap';
+
+
+(: This variable contains the information of the account on the IMAP server. :)
+let $hostInfo :=
+ <hostInfo xmlns="http://www.zorba-xquery.com/modules/email";>
+ <hostName>mail.28msec.com/novalidate-cert</hostName>
+ <userName>imaptest</userName>
+ <password>cclient</password>
+ </hostInfo>
+
+return
+ imap:search($hostInfo, "INBOX", "SUBJECT test", true())
=== added file 'examples/Queries/imap/set_flags_example.xq'
--- examples/Queries/imap/set_flags_example.xq 1970-01-01 00:00:00 +0000
+++ examples/Queries/imap/set_flags_example.xq 2014-04-30 23:07:12 +0000
@@ -0,0 +1,35 @@
+(:
+ : This example shows how to use the set-flags function of the
+ : http://www.zorba-xquery.com/modules/email/imap module.
+ :
+ : First, the unique identifiers of all messages containing the word "flags" in
+ : the subject are retrieved. Then, the flags of the first of the message found
+ : are set to "seen" and "answered".
+ :
+ : The message will henceforth have exactly the flags that were set using the
+ : XML structure, so all the existing flag before this call are lost.
+ :
+ : If no error is thrown, all operations were successful.
+ :)
+
+import module namespace imap = 'http://www.zorba-xquery.com/modules/email/imap';
+
+
+(: This variable contains the information of the account on the IMAP server. :)
+let $hostInfo :=
+ <hostInfo xmlns="http://www.zorba-xquery.com/modules/email";>
+ <hostName>mail.28msec.com/novalidate-cert</hostName>
+ <userName>imaptest</userName>
+ <password>cclient</password>
+ </hostInfo>
+
+let $uids := imap:search($hostInfo, "INBOX", "SUBJECT flags", true())
+
+let $flags :=
+ <flags xmlns="http://www.zorba-xquery.com/modules/email";>
+ <seen/>
+ <answered/>
+ </flags>
+
+return
+ imap:set-flags($hostInfo, "INBOX", $uids[1], $flags, true())
\ No newline at end of file
=== added file 'examples/Queries/imap/status_example.xq'
--- examples/Queries/imap/status_example.xq 1970-01-01 00:00:00 +0000
+++ examples/Queries/imap/status_example.xq 2014-04-30 23:07:12 +0000
@@ -0,0 +1,33 @@
+(:
+ : This example shows how to use the status function of the
+ : http://www.zorba-xquery.com/modules/email/imap module.
+ :
+ : Using the host information stored in the variable $hostInfo, the account
+ : status of the user imaptest on the mail.28msec.com server is retrieved.
+ :
+ : The XML output of this script should look something like:
+ :
+ : <status xmlns:imaps="http://www.zorba-xquery.com/modules/email";>
+ : <messages>27</messages>
+ : <recent>0</recent>
+ : <unseen>5</unseen>
+ : <uidnext>77</uidnext>
+ : <uidvalidity>1285079359</uidvalidity>
+ : </status>
+ :
+ : If no error is thrown, all operations were successful.
+ :)
+
+import module namespace imap = 'http://www.zorba-xquery.com/modules/email/imap';
+
+
+(: This variable contains the information of the account on the IMAP server. :)
+let $hostInfo :=
+ <hostInfo xmlns="http://www.zorba-xquery.com/modules/email";>
+ <hostName>mail.28msec.com/novalidate-cert</hostName>
+ <userName>imaptest</userName>
+ <password>cclient</password>
+ </hostInfo>
+
+return
+ imap:status($hostInfo, "INBOX")
=== added file 'examples/Queries/imap/subscribe_unsubscribe_example.xq'
--- examples/Queries/imap/subscribe_unsubscribe_example.xq 1970-01-01 00:00:00 +0000
+++ examples/Queries/imap/subscribe_unsubscribe_example.xq 2014-04-30 23:07:12 +0000
@@ -0,0 +1,29 @@
+(:
+ : This example shows how to use the subscribe and unsubscribe functions of the
+ : http://www.zorba-xquery.com/modules/email/imap module.
+ :
+ : Using the host information stored in the variable $hostInfo the user
+ : imaptest is subscribed to the folder INBOX.Test on the account. After this,
+ : the user is unsubscribed from this folder using the unsubscribe function.
+ :
+ : Subscribing to a folder will make the folder visible for email clients that
+ : by default only list the subscribed folders.
+ :
+ : If no error is thrown, all operations were successful.
+ :)
+
+import module namespace imap = 'http://www.zorba-xquery.com/modules/email/imap';
+
+(: This variable contains the information of the account on the IMAP server. :)
+let $hostInfo :=
+ <hostInfo xmlns="http://www.zorba-xquery.com/modules/email";>
+ <hostName>mail.28msec.com/novalidate-cert</hostName>
+ <userName>imaptest</userName>
+ <password>cclient</password>
+ </hostInfo>
+
+return
+ {
+ imap:subscribe($hostInfo, "INBOX.Test");
+ imap:unsubscribe($hostInfo, "INBOX.Test")
+ }
=== added directory 'examples/Queries/smtp'
=== added file 'examples/Queries/smtp/html.xq'
--- examples/Queries/smtp/html.xq 1970-01-01 00:00:00 +0000
+++ examples/Queries/smtp/html.xq 2014-04-30 23:07:12 +0000
@@ -0,0 +1,57 @@
+(:
+ : This example uses the send function of the SMTP module to send an email
+ : containing an HTML message from a GMail account.
+ : This message is also sent to the sender itself in CC.
+ :)
+
+import module namespace smtp = 'http://www.zorba-xquery.com/modules/email/smtp';
+
+
+(: Note the use of the serialize function to create a string from the HTML content. :)
+let $htmlContent := fn:serialize(
+ <html>
+ <head></head>
+ <body>
+ <h1>Zorba really rocks.</h1>
+ <p>XQuery brought to a new level</p>
+ </body>
+ </html>
+ )
+
+(: This variable contains the information of the account from which the email should be sent. :)
+let $hostInfo :=
+ <hostInfo xmlns="http://www.zorba-xquery.com/modules/email";>
+ <hostName>smtp.gmail.com:587/tls/novalidate-cert</hostName>
+ <userName>zorba.smtp.sender</userName>
+ <password>1openssl!!</password>
+ </hostInfo>
+
+(: the XML representation of the email to be sent, as described by the XML schema
+ http://www.zorba-xquery.com/modules/email :)
+let $email :=
+ <message xmlns="http://www.zorba-xquery.com/modules/email";>
+ <envelope>
+ <date>2010-11-26T15:50:39-04:01</date>
+ <subject>An important HTML message</subject>
+ <recipient>
+ <to>
+ <name>Test Account</name>
+ <email>imaptest@xxxxxxxxxx</email>
+ </to>
+ </recipient>
+ <recipient>
+ <cc>
+ <name>Myself</name>
+ <email>zorba.smtp.sender@xxxxxxxxx</email>
+ </cc>
+ </recipient>
+ </envelope>
+ <body>
+ <content contentType="text/html" charset="UTF-8" contentTransferEncoding="ENC8BIT">{
+ $htmlContent
+ }</content>
+ </body>
+ </message>
+
+return
+ smtp:send($hostInfo, $email)
=== added file 'examples/Queries/smtp/html_text_alternative.xq'
--- examples/Queries/smtp/html_text_alternative.xq 1970-01-01 00:00:00 +0000
+++ examples/Queries/smtp/html_text_alternative.xq 2014-04-30 23:07:12 +0000
@@ -0,0 +1,68 @@
+(:
+ : This example uses the send function of the SMTP module to send an email
+ : containing an HTML and text message from a GMail account. The order of the
+ : alternative contents might be relevant for some email clients. There is
+ : though a rule of thumb saying that the alternatives must be ordered in from
+ : the least to the most faithful representation. That is in our case, HTML
+ : version comes after the text version. This way email clients can stop at the
+ : email version they can still process. This message is also sent to the sender
+ : itself in CC.
+ :)
+
+import module namespace smtp = 'http://www.zorba-xquery.com/modules/email/smtp';
+
+
+(: Note the use of the serialize function to create a string from the HTML content. :)
+let $htmlContent := fn:serialize(
+ <html>
+ <head></head>
+ <body>
+ <h1>Zorba really rocks.</h1>
+ <p>XQuery brought to a new level</p>
+ </body>
+ </html>
+ )
+let $textContent := "Simple text version ... get yourself a nice and fancy email client."
+
+(: This variable contains the information of the account from which the email should be sent. :)
+let $hostInfo :=
+ <hostInfo xmlns="http://www.zorba-xquery.com/modules/email";>
+ <hostName>smtp.gmail.com:587/tls/novalidate-cert</hostName>
+ <userName>zorba.smtp.sender</userName>
+ <password>1openssl!!</password>
+ </hostInfo>
+
+(: the XML representation of the email to be sent, as described by the XML schema
+ http://www.zorba-xquery.com/modules/email :)
+let $email :=
+ <message xmlns="http://www.zorba-xquery.com/modules/email";>
+ <envelope>
+ <date>2010-11-26T15:50:39-04:01</date>
+ <subject>An important HTML or Text message</subject>
+ <recipient>
+ <to>
+ <name>Test Account</name>
+ <email>imaptest@xxxxxxxxxx</email>
+ </to>
+ </recipient>
+ <recipient>
+ <cc>
+ <name>Myself</name>
+ <email>zorba.smtp.sender@xxxxxxxxx</email>
+ </cc>
+ </recipient>
+ </envelope>
+ <body>
+ <multipart contentType="multipart/alternative" charset="UTF-8" contentTransferEncoding="ENC8BIT">
+ <content contentType="text/html" charset="UTF-8" contentTransferEncoding="ENC8BIT">{
+ $htmlContent
+ }</content>
+ <content contentType="text/plain" charset="UTF-8" contentTransferEncoding="ENC8BIT">{
+ $textContent
+ }</content>
+ </multipart>
+ </body>
+ </message>
+
+return
+ smtp:send($hostInfo, $email)
=== added file 'examples/Queries/smtp/simple_text.xq'
--- examples/Queries/smtp/simple_text.xq 1970-01-01 00:00:00 +0000
+++ examples/Queries/smtp/simple_text.xq 2014-04-30 23:07:12 +0000
@@ -0,0 +1,39 @@
+(:
+ : This example uses the send function of the SMTP module to send an email
+ : containing a simple text message from a GMail account.
+ :)
+
+import module namespace smtp = 'http://www.zorba-xquery.com/modules/email/smtp';
+
+
+(: This variable contains the information of the account from which the email should be sent. :)
+let $hostInfo :=
+ <hostInfo xmlns="http://www.zorba-xquery.com/modules/email";>
+ <hostName>smtp.gmail.com:587/tls/novalidate-cert</hostName>
+ <userName>zorba.smtp.sender</userName>
+ <password>1openssl!!</password>
+ </hostInfo>
+
+(: the XML representation of the email to be sent, as described by the XML schema
+ http://www.zorba-xquery.com/modules/email :)
+let $email :=
+ <message xmlns="http://www.zorba-xquery.com/modules/email";>
+ <envelope>
+ <date>2010-11-26T15:50:39-04:01</date>
+ <subject>An important message</subject>
+ <recipient>
+ <to>
+ <name>Test Account</name>
+ <email>imaptest@xxxxxxxxxx</email>
+ </to>
+ </recipient>
+ </envelope>
+ <body>
+ <content contentType="text/plain" charset="UTF-8" contentTransferEncoding="ENC8BIT">
+ Zorba really rocks.
+ </content>
+ </body>
+ </message>
+
+return
+ smtp:send($hostInfo, $email)
=== added file 'examples/Queries/smtp/text_with_image.xq'
--- examples/Queries/smtp/text_with_image.xq 1970-01-01 00:00:00 +0000
+++ examples/Queries/smtp/text_with_image.xq 2014-04-30 23:07:12 +0000
@@ -0,0 +1,62 @@
+(:
+ : This example uses the send function of the SMTP module to send an email
+ : containing a simple text message with an image as attachement from a GMail
+ : account.
+ : To make things really interesting, the image is made on the spot with the
+ : help o the image modules available in Zorba.
+ :)
+
+import module namespace smtp = 'http://www.zorba-xquery.com/modules/email/smtp';
+import module namespace basic = 'http://www.zorba-xquery.com/modules/image/basic';
+import module namespace paint = 'http://www.zorba-xquery.com/modules/image/paint';
+
+
+(: This variable contains the information of the account from which the email should be sent. :)
+let $hostInfo :=
+ <hostInfo xmlns="http://www.zorba-xquery.com/modules/email";>
+ <hostName>smtp.gmail.com:587/tls/novalidate-cert</hostName>
+ <userName>zorba.smtp.sender</userName>
+ <password>1openssl!!</password>
+ </hostInfo>
+
+(: The base64 representation of the image to be sent. :)
+let $image := paint:paint(
+ basic:create(xs:unsignedInt(200), xs:unsignedInt(200), "GIF"),
+ <text xmlns="http://www.zorba-xquery.com/modules/image/image";>
+ <origin><x>20</x><y>50</y></origin>
+ <text>Zorba really rocks.</text>
+ <font>Arial</font>
+ <font-size>14</font-size>
+ </text>)
+
+(: the XML representation of the email to be sent, as described by the XML schema
+ http://www.zorba-xquery.com/modules/email :)
+let $email :=
+ <message xmlns="http://www.zorba-xquery.com/modules/email";>
+ <envelope>
+ <date>2010-11-26T15:50:39-04:01</date>
+ <subject>An important Image message</subject>
+ <recipient>
+ <to>
+ <name>Test Account</name>
+ <email>imaptest@xxxxxxxxxx</email>
+ </to>
+ </recipient>
+ </envelope>
+ <body>
+ <multipart contentType="multipart/mixed" charset="UTF-8" contentTransferEncoding="ENC8BIT">
+ <content contentType="text/plain" charset="UTF-8" contentTransferEncoding="ENC8BIT">
+ Zorba really rocks.
+ </content>
+ <content contentType="image/gif" charset="UTF-8" contentTransferEncoding="ENCBASE64"
+ contentDisposition="attachement" contentDisposition-filename="the-truth.gif">{
+
+ $image
+
+ }</content>
+ </multipart>
+ </body>
+ </message>
+
+return
+ smtp:send($hostInfo, $email)
=== added directory 'src'
=== renamed directory 'src' => 'src.moved'
=== added file 'src/CMakeLists.txt'
--- src/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ src/CMakeLists.txt 2014-04-30 23:07:12 +0000
@@ -0,0 +1,20 @@
+# Copyright 2006-2008 The FLWOR Foundation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# all external module libraries are generated in the directory
+# of the corresponding .xq file
+MESSAGE(STATUS "Add com")
+ADD_SUBDIRECTORY(com)
+
+MESSAGE(STATUS "End modules")
=== added directory 'src/com'
=== added file 'src/com/CMakeLists.txt'
--- src/com/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ src/com/CMakeLists.txt 2014-04-30 23:07:12 +0000
@@ -0,0 +1,14 @@
+# Copyright 2006-2008 The FLWOR Foundation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+ADD_SUBDIRECTORY(zorba-xquery)
=== added directory 'src/com/zorba-xquery'
=== added file 'src/com/zorba-xquery/CMakeLists.txt'
--- src/com/zorba-xquery/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ src/com/zorba-xquery/CMakeLists.txt 2014-04-30 23:07:12 +0000
@@ -0,0 +1,14 @@
+# Copyright 2006-2008 The FLWOR Foundation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+ADD_SUBDIRECTORY(www)
=== added directory 'src/com/zorba-xquery/www'
=== added file 'src/com/zorba-xquery/www/CMakeLists.txt'
--- src/com/zorba-xquery/www/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ src/com/zorba-xquery/www/CMakeLists.txt 2014-04-30 23:07:12 +0000
@@ -0,0 +1,14 @@
+# Copyright 2006-2008 The FLWOR Foundation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+ADD_SUBDIRECTORY(modules)
=== added directory 'src/com/zorba-xquery/www/modules'
=== added file 'src/com/zorba-xquery/www/modules/CMakeLists.txt'
--- src/com/zorba-xquery/www/modules/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ src/com/zorba-xquery/www/modules/CMakeLists.txt 2014-04-30 23:07:12 +0000
@@ -0,0 +1,14 @@
+# Copyright 2006-2008 The FLWOR Foundation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+ADD_SUBDIRECTORY(email)
=== added directory 'src/com/zorba-xquery/www/modules/email'
=== added file 'src/com/zorba-xquery/www/modules/email/CMakeLists.txt'
--- src/com/zorba-xquery/www/modules/email/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ src/com/zorba-xquery/www/modules/email/CMakeLists.txt 2014-04-30 23:07:12 +0000
@@ -0,0 +1,87 @@
+# Copyright 2006-2008 The FLWOR Foundation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# CClient library part of the UW IMAP toolkit required by the email
+# functionality
+IF (ZORBA_SUPPRESS_CCLIENT)
+ MESSAGE(STATUS "ZORBA_SUPPRESS_CCLIENT is true - not searching for C-Client")
+ELSE(ZORBA_SUPPRESS_CCLIENT)
+ MESSAGE (STATUS "Looking for CClient")
+ FIND_PACKAGE (CClient)
+
+ IF (NOT WIN32 AND NOT CYGWIN)
+ FIND_PACKAGE(OpenSSL)
+ FIND_PACKAGE(PAM)
+ FIND_PACKAGE(Kerberos)
+ ENDIF (NOT WIN32 AND NOT CYGWIN)
+
+ IF(CCLIENT_FOUND)
+ SET(SMTP_LINK_LIBRARIES ${CCLIENT_LIBRARIES})
+
+ IF (OPENSSL_FOUND)
+ LIST(APPEND SMTP_LINK_LIBRARIES ${OPENSSL_LIBRARIES})
+ LIST(APPEND SMTP_LINK_LIBRARIES ${OPENSSL_CRYPTO_LIBRARIES})
+ ELSE (OPENSSL_FOUND)
+ MESSAGE(STATUS "CClient library found but OpenSSL not found. This may cause runtime problems on certain platforms where CClient is linked against OpenSSL by default, including MacOS X and Ubuntu Linux (and probably others). See this module's README.txt for more information.")
+ ENDIF (OPENSSL_FOUND)
+
+ # Mac Ports and Ubuntu compiles CCLient with kerberos support by default.
+ IF(KERBEROS_FOUND)
+ LIST(APPEND SMTP_LINK_LIBRARIES ${KERBEROS_LIBRARY})
+ ELSE (KERBEROS_FOUND)
+ MESSAGE(STATUS "CClient library found but Kerberos not found. This may cause runtime problems on certain platforms where CClient is linked against Kerberos by default, including MacOS X and Ubuntu Linux (and probably others). See this module's README.txt for more information.")
+ ENDIF (KERBEROS_FOUND)
+
+ INCLUDE_DIRECTORIES(${CCLIENT_INCLUDE_DIRS})
+ IF (NOT WIN32 AND NOT CYGWIN)
+ LIST(APPEND SMTP_LINK_LIBRARIES ${PAM_LIBRARIES})
+ ELSE (NOT WIN32 AND NOT CYGWIN)
+ LIST(APPEND SMTP_LINK_LIBRARIES secur32.lib crypt32.lib winmm.lib ws2_32.lib)
+ ENDIF (NOT WIN32 AND NOT CYGWIN)
+
+ # including shared c-client library
+ ADD_LIBRARY (imap_commons STATIC
+ cclient/imap_client.cpp
+ cclient/email_exception.cpp
+ )
+ SET_TARGET_PROPERTIES (imap_commons PROPERTIES
+ FOLDER "Modules"
+ )
+
+ IF(UNIX AND NOT WIN32)
+ ADD_DEFINITIONS(-fPIC)
+
+ # option needed to make c-client compilable with clang
+ IF (CLANG)
+ SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fms-compatibility")
+ ENDIF()
+
+ ENDIF(UNIX AND NOT WIN32)
+
+ TARGET_LINK_LIBRARIES(imap_commons ${SMTP_LINK_LIBRARIES})
+ INCLUDE_DIRECTORIES("cclient")
+
+
+ DECLARE_ZORBA_SCHEMA (FILE email.xsd
+ URI "http://www.zorba-xquery.com/modules/email";)
+ DECLARE_ZORBA_MODULE (URI "http://www.zorba-xquery.com/modules/email/smtp"; VERSION 1.0 FILE "smtp.xq" LINK_LIBRARIES "imap_commons;${SMTP_LINK_LIBRARIES}")
+ DECLARE_ZORBA_MODULE (URI "http://www.zorba-xquery.com/modules/email/imap"; VERSION 1.0 FILE "imap.xq" LINK_LIBRARIES "imap_commons;${SMTP_LINK_LIBRARIES}")
+
+ ELSE(CCLIENT_FOUND)
+
+ MESSAGE(STATUS "CClient library not found -- if you want to use Email functionality please set CCLIENT_INCLUDE_DIRS and CCLIENT_LIBRARIES parameters.")
+
+ ENDIF(CCLIENT_FOUND)
+ENDIF(ZORBA_SUPPRESS_CCLIENT)
+MESSAGE(STATUS "")
=== added file 'src/com/zorba-xquery/www/modules/email/README.txt'
--- src/com/zorba-xquery/www/modules/email/README.txt 1970-01-01 00:00:00 +0000
+++ src/com/zorba-xquery/www/modules/email/README.txt 2014-04-30 23:07:12 +0000
@@ -0,0 +1,50 @@
+These library modules need the c-client library installed to work properly.
+Here are a few notes that should help in doing this.
+
+Building IMAP CClient
+
+Zorba provides email (smtp and imap) support using the CClient library part of thei UW IMAP toolkit found at http://www.washington.edu/imap/.
+
+Unix/Linux/Mac OS
+Notes:
+ - There are some known issues with the CClient packages that come with diffrent Linux distributions.
+ - On x32 bit OpenSuse and also on x64 bit Ubuntu we noticed that the CClient shared library is broken (undefined symbol: mm_dlog).
+ - Due to that fact that Mark Crispin (the creator of CClient library) does not support CClient as a shared library but only as a static library (see FAQs shared library at http://www.washington.edu/imap/IMAP-FAQs/index.html#6.3), we strongly suggest you want to get the UW IMAP toolkit</a> and compile it yourself.
+- On Linux 64-bit, you might discover a problem with the optional package cclient. E.g. on Ubuntu 64-bit, you might discover the following:
+
+Linking CXX shared library libsmtp.so
+/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/4.4.3/../../../../lib/libc-client.a(osdep.o): relocation R_X86_64_32 against
+ `server_input_wait' can not be used when making a shared object; recompile with -fPIC
+/usr/lib/gcc/x86_64-linux-gnu/4.4.3/../../../../lib/libc-client.a: could not read symbols: Bad value
+e
+ To fix this, you need to compile CClient yourself. The commands to compile CClient correctly are:
+
+cd <some_directory>
+wget ftp://ftp.cac.washington.edu/imap/imap-2007e.tar.gz
+tar -xf imap-2007e.tar.gz
+cd imap-2007e
+make slx EXTRACFLAGS="-I/usr/include/openssl -fPIC"
+
+
+ - Also please keep in mind that if SSL/TLS authentication is required by the SMTP server, then you first need to install OpenSSL found at http://www.openssl.org/ and configure CClient to use it.
+ - Make sure the name of the library is prefixed by 'lib' and suffixed with '.a' (for example libc-client.a on Linux/Unix or libc-client4.a on Mac OS).
+
+Use the following extra CMake arguments when building Zorba:
+
+-D CCLIENT_INCLUDE="path_to_imap-2007e\c-client"
+-D CCLIENT_LIBRARY="path_to_imap-2007e\c-client\libc-client.a"
+
+Here are some quick suggestions to build CClient on Linux:
+- x32-bit Linux: make lnp
+- x64-bit Linux: make lnp EXTRACFLAGS="-I/usr/include/openssl -fPIC" EXTRAAUTHENTICATORS=gss in order to build with SSL and Kerberos support.
+
+For more detailed build instructions please check out the Server Documentation at http://www.washington.edu/imap/documentation and the UW IMAP FAQs at http://www.washington.edu/imap/IMAP-FAQs/index.html
+
+Windows
+You must build the UW IMAP toolkit yourself.
+
+Use the following extra CMake arguments when building Zorba:
+
+-D "CCLIENT_INCLUDE=path_to_imap-2007e\c-client"
+-D "CCLIENT_LIBRARY=path_to_imap-2007e\c-client\release\cclient.lib"
+
=== added directory 'src/com/zorba-xquery/www/modules/email/cclient'
=== added file 'src/com/zorba-xquery/www/modules/email/cclient/email_exception.cpp'
--- src/com/zorba-xquery/www/modules/email/cclient/email_exception.cpp 1970-01-01 00:00:00 +0000
+++ src/com/zorba-xquery/www/modules/email/cclient/email_exception.cpp 2014-04-30 23:07:12 +0000
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "email_exception.h"
+
+
+namespace zorba { namespace emailmodule {
+
+EmailException::EmailException(
+ const std::string& aLocalName,
+ const std::string& msg) throw()
+ : theLocalName(aLocalName), theMessage(msg)
+{
+}
+
+EmailException::~EmailException() throw()
+{
+}
+
+const char*
+EmailException::what() const throw()
+{
+ return theMessage.c_str();
+}
+
+const std::string&
+EmailException::get_message() const
+{
+ return theMessage;
+}
+
+const std::string&
+EmailException::get_localname() const
+{
+ return theLocalName;
+}
+
+} // namespace emailmodule
+} // namespace zorba
=== added file 'src/com/zorba-xquery/www/modules/email/cclient/email_exception.h'
--- src/com/zorba-xquery/www/modules/email/cclient/email_exception.h 1970-01-01 00:00:00 +0000
+++ src/com/zorba-xquery/www/modules/email/cclient/email_exception.h 2014-04-30 23:07:12 +0000
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ZORBA_EMAILMODULE_EMAILEXCEPTION_H
+#define ZORBA_EMAILMODULE_EMAILEXCEPTION_H
+
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+#include "c-client.h"
+#include <string>
+#undef max
+#include <list>
+#include <vector>
+#include <exception>
+#include <sstream>
+
+namespace zorba { namespace emailmodule {
+
+class EmailException : std::exception
+{
+ public:
+ explicit EmailException(
+ const std::string& aLocalName,
+ const std::string& message) throw();
+
+ virtual ~EmailException() throw();
+
+ virtual const char*
+ what() const throw();
+
+ const std::string&
+ get_message() const;
+
+ const std::string&
+ get_localname() const;
+
+ private:
+ std::string theLocalName;
+ std::string theMessage;
+};
+
+} // namespace emailmodule
+} // namespace zorba
+
+#endif // ZORBA_EMAILMODULE_EMAILEXCEPTION_H
=== added file 'src/com/zorba-xquery/www/modules/email/cclient/imap_client.cpp'
--- src/com/zorba-xquery/www/modules/email/cclient/imap_client.cpp 1970-01-01 00:00:00 +0000
+++ src/com/zorba-xquery/www/modules/email/cclient/imap_client.cpp 2014-04-30 23:07:12 +0000
@@ -0,0 +1,938 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "imap_client.h"
+
+#include <stdio.h>
+#include <iostream>
+#include <sstream>
+#include <vector>
+
+#include "email_exception.h"
+
+#ifndef WIN32
+#pragma GCC diagnostic ignored "-Wwrite-strings"
+#endif
+
+
+namespace zorba { namespace emailmodule {
+
+ // functions for smtp support
+
+ bool
+ ImapClient::send(const std::string& aHost,
+ const std::string& aUsername,
+ const std::string& aPassword,
+ ENVELOPE* aEnvelope,
+ BODY* aBody,
+ std::stringstream& aDiagnostics) {
+
+
+
+ setUserName(aUsername);
+ setPassword(aPassword);
+
+ std::stringstream out;
+ char tmp[MAILTMPLEN];
+ SENDSTREAM *smtp_stream = NIL;
+ bool res = false;
+
+ char *hostlist[2];
+ hostlist[0] = const_cast<char*>(aHost.c_str());
+ hostlist[1] = NIL;
+
+#include "linkage.c"
+#if MACOS
+ {
+ size_t *base = (size_t *) 0x000908;
+ // increase stack size on a Mac
+ SetApplLimit ((Ptr) (*base - (size_t) 65535L));
+ }
+#endif
+
+ out << "Sending..." << std::endl;
+ smtp_stream = smtp_open (hostlist,0);
+ if ( smtp_stream ) {
+ if ( smtp_stream->replycode >= 400 ) {
+ out << smtp_stream->reply << std::endl;
+ }
+ else {
+ sprintf (tmp, "MAIL");
+ res = smtp_mail(smtp_stream, tmp, aEnvelope, aBody) != 0;
+ if (res) {
+ out << "Ok.";
+ } else {
+ out << "Failed.";
+ out << std::endl << "Reply: " << smtp_stream->reply;
+ // Check if it was a problem with the reciptients
+ ADDRESS* lAdresses[4] = {aEnvelope->from, aEnvelope->to, aEnvelope->cc, aEnvelope->bcc};
+ for (int i = 0; i < 4; ++i) {
+ ADDRESS* lAddress = lAdresses[i];
+ while (lAddress) {
+ if (lAddress->error) {
+ out << std::endl << "\tProblem with address " << lAddress->mailbox << "@" << lAddress->host << ": " << aEnvelope->to->error;
+ }
+ lAddress = lAddress->next;
+ }
+ }
+ }
+ smtp_close(smtp_stream);
+ }
+ } else {
+ out << "Opening connection to " << aHost << " failed." << std::endl;
+ }
+
+ aDiagnostics << out.str();
+ return res;
+
+
+ }
+
+
+ // functions for imap support
+ void
+ ImapClient::setUserName(const std::string& usr) {
+ theUserName = usr;
+ }
+
+ void
+ ImapClient::setPassword(const std::string& pwd) {
+ thePassword = pwd;
+ }
+
+ std::string
+ ImapClient::getUserName() {
+ return theUserName;
+ }
+
+ std::string
+ ImapClient::getPassword() {
+ return thePassword;
+ }
+
+ MAILSTREAM*
+ ImapClient::getMailStream(const std::string& aHost,
+ const std::string& aUsername,
+ const std::string& aPassword,
+ const std::string& aMailbox,
+ const bool aFullOpen) {
+ std::string lHostAndMailbox = "{" + aHost + "}" + aMailbox;
+
+ // check if there is a mailstream that is already open with the same parameters, if true then take it (this is the ideal case)
+
+ int lNumberOfKnownHosts = (int)theHosts.size();
+ std::list<Host>::iterator allHostsIterator;
+ for (allHostsIterator = theHosts.begin(); allHostsIterator != theHosts.end(); allHostsIterator++) {
+ if (((*allHostsIterator).lMailStream) &&
+ ((*allHostsIterator).lUsername.compare(aUsername) == 0) &&
+ ((*allHostsIterator).lPassword.compare(aPassword) == 0) &&
+ ((*allHostsIterator).lHostNameWithMailbox.compare(lHostAndMailbox) == 0)) {
+
+ // if we already have mailstream but it is not full open yet, then open it again, this time full
+ if ((*allHostsIterator).lIsFullOpen == false && aFullOpen == true) {
+ setUserName((*allHostsIterator).lUsername);
+ setPassword((*allHostsIterator).lPassword);
+ mail_open((*allHostsIterator).lMailStream, const_cast<char*>(lHostAndMailbox.c_str()), NIL);
+ (*allHostsIterator).lIsFullOpen = true;
+
+ }
+ return (*allHostsIterator).lMailStream;
+ }
+ }
+ // if we found an existing mailstream, then everything is ok, if not we have to make a new one
+ Host lNewHost;
+ lNewHost.lUsername = aUsername;
+ lNewHost.lPassword = aPassword;
+ lNewHost.lHostNameWithMailbox = lHostAndMailbox;
+ lNewHost.lIsFullOpen = aFullOpen;
+ // if we already have more then 7 open mailstreams, close the last one to make place
+ if (lNumberOfKnownHosts == 7) {
+ Host lToDelete = theHosts.back();
+ theHosts.pop_back();
+ mail_close(lToDelete.lMailStream);
+ }
+
+ setUserName(aUsername);
+ setPassword(aPassword);
+
+ lNewHost.lMailStream = mail_open(NIL, const_cast<char*>(lHostAndMailbox.c_str()), (aFullOpen ? NIL : OP_HALFOPEN));
+ theHosts.push_front(lNewHost);
+
+ checkMailStream(lNewHost.lMailStream);
+ return lNewHost.lMailStream;
+ }
+
+
+ void
+ ImapClient::status (const std::string& aHost,
+ const std::string& aUsername,
+ const std::string& aPassword,
+ const std::string& aMailbox)
+ {
+#include "linkage.c"
+ std::string lHostAndMailbox = "{" + aHost + "}" ;
+ MAILSTREAM* lSource = getMailStream(aHost, aUsername, aPassword, aMailbox, false);
+ mail_status (lSource, const_cast<char*>(lHostAndMailbox.c_str()), SA_MESSAGES | SA_RECENT | SA_UNSEEN | SA_UIDNEXT | SA_UIDVALIDITY);
+ }
+
+ bool
+ ImapClient::create (const std::string& aHost,
+ const std::string& aUsername,
+ const std::string& aPassword,
+ const std::string& aMailbox) {
+
+#include "linkage.c"
+ MAILSTREAM* lSource = getMailStream(aHost, aUsername, aPassword, aMailbox, false);
+ std::string lFullName = "{" + aHost + "}" + aMailbox;
+ return (mail_create (lSource, const_cast<char*>(lFullName.c_str())) == T);
+ }
+
+
+ bool
+ ImapClient::delete_mailbox (const std::string& aHost,
+ const std::string& aUsername,
+ const std::string& aPassword,
+ const std::string& aMailbox) {
+
+#include "linkage.c"
+ MAILSTREAM *lSource = getMailStream(aHost, aUsername, aPassword, aMailbox, false);
+ std::string lFullName = "{" + aHost + "}" + aMailbox;
+ return (mail_delete(lSource, const_cast<char*>(lFullName.c_str())) == T);
+ }
+
+ bool
+ ImapClient::rename (const std::string& aHost,
+ const std::string& aUsername,
+ const std::string& aPassword,
+ const std::string& aFromMailbox,
+ const std::string& aToMailbox) {
+
+#include "linkage.c"
+ MAILSTREAM* lSource = getMailStream(aHost, aUsername, aPassword, "", false);
+ std::string lHost = "{" + aHost + "}";
+ std::string lFullNameOld = lHost + aFromMailbox;
+ std::string lFullNameNew = lHost + aToMailbox;
+ return (mail_rename(lSource, const_cast<char*>(lFullNameOld.c_str()), const_cast<char*>( lFullNameNew.c_str())) == T);
+ }
+
+ bool
+ ImapClient::subscription(const std::string& aHost,
+ const std::string& aUsername,
+ const std::string& aPassword,
+ const std::string& aMailbox,
+ bool subscribe) {
+
+#include "linkage.c"
+ std::string lHost = "{" + aHost + "}";
+ MAILSTREAM* lSource = getMailStream(aHost, aUsername, aPassword, aMailbox, false);
+ std::string lFullName = lHost + aMailbox;
+ if (subscribe) {
+ return (mail_subscribe(lSource, const_cast<char*>(lFullName.c_str())) == T);
+ } else {
+ return (mail_unsubscribe(lSource, const_cast<char*>(lFullName.c_str())) == T);
+ }
+ }
+
+
+ bool
+ ImapClient::expunge(const std::string& aHost,
+ const std::string& aUsername,
+ const std::string& aPassword,
+ const std::string& aMailbox) {
+
+#include "linkage.c"
+ std::string lHost = "{" + aHost + "}" + aMailbox;
+ MAILSTREAM* lSource = getMailStream(aHost, aUsername, aPassword, aMailbox, true);
+ if (lSource) { mail_expunge(lSource); }
+ return true;
+ }
+
+
+ std::vector<std::string>
+ ImapClient::list(const std::string& aHost,
+ const std::string& aUsername,
+ const std::string& aPassword,
+ const std::string& aReferencePath,
+ const std::string& aPattern,
+ bool aOnlySuscribed) {
+
+#include "linkage.c"
+ /* IMPORTANT: make sure that the vector of listed mailboxes is empty! */
+ theListedMailboxes.clear();
+
+ std::string lHost = "{" + aHost + "}";
+ MAILSTREAM* lSource = getMailStream(aHost, aUsername, aPassword, "", false);
+ std::string lFullPath = lHost + aReferencePath;
+ if (aOnlySuscribed) {
+ mail_lsub(lSource, const_cast<char*>(lFullPath.c_str()), const_cast<char*>(aPattern.c_str()));
+ } else {
+ mail_list(lSource, const_cast<char*>(lFullPath.c_str()), const_cast<char*>(aPattern.c_str()));
+ }
+ // theListedMailbox is filled through the mm_list or mm_listsub callback functions
+ return theListedMailboxes;
+ }
+
+ bool
+ ImapClient::copy(const std::string& aHost,
+ const std::string& aUserName,
+ const std::string& aPassword,
+ const std::string& aMailboxFrom,
+ const std::string& aMailboxTo,
+ const std::string& aMessageNumbers,
+ bool aUid,
+ bool aCopy) {
+
+#include "linkage.c"
+
+ std::string lHost = "{" + aHost + "}" + aMailboxFrom;
+ MAILSTREAM* lSource = getMailStream(aHost, aUserName, aPassword, aMailboxFrom, true);
+ long lLongResult = mail_copy_full(lSource, const_cast<char*>(aMessageNumbers.c_str()), const_cast<char*>(aMailboxTo.c_str()), (aUid ? SE_UID : NIL) | (aCopy ? NIL : CP_MOVE));
+ return (lLongResult == T);
+ }
+
+ std::vector<long>
+ ImapClient::search(const std::string& aHost,
+ const std::string& aUsername,
+ const std::string& aPassword,
+ const std::string& aMailbox,
+ const std::string& aCriteria,
+ bool aUid) {
+
+#include "linkage.c"
+
+ /* IMPORTANT: make sure that the vector of found sequence numbers is empty! */
+ theFoundSequenceNumbers.clear();
+
+ MAILSTREAM* lSource = getMailStream(aHost, aUsername, aPassword, aMailbox, true);
+ checkMailStream(lSource);
+ mail_ping(lSource);
+
+
+ /* First, tokenize the criteria so that we can work on it */
+ std::stringstream lToTokenize(aCriteria);
+ std::string lBuffer;
+ std::vector<std::string> lTokens;
+
+ SEARCHPGM * lSearchProgram;
+ while(lToTokenize >> lBuffer) {
+ lTokens.push_back(lBuffer);
+ }
+ lSearchProgram = search_criteria(lTokens);
+
+ mail_search_full(lSource, NIL, lSearchProgram, (aUid ? SE_UID : NIL) | SE_NOPREFETCH);
+ /* clean up, don't leave a mess */
+ mail_free_searchpgm(&lSearchProgram);
+ return theFoundSequenceNumbers;
+ }
+
+ ENVELOPE *
+ ImapClient::fetchEnvelope(const std::string& aHost,
+ const std::string& aUsername,
+ const std::string& aPassword,
+ const std::string& aMailbox,
+ unsigned long aMessageNumber,
+ std::vector<int>& aFlagsVector,
+ const bool aUid)
+ {
+#include "linkage.c"
+ MAILSTREAM* lSource = getMailStream(aHost, aUsername, aPassword, aMailbox, true);
+
+ if (aUid) {
+ aMessageNumber = mail_msgno(lSource, aMessageNumber);
+ }
+
+ ENVELOPE* lResult = mail_fetchenvelope(lSource, aMessageNumber);
+
+ if (!lResult) {
+ throw EmailException("WRONG_ID", "Could not get message - wrong message id.");
+ }
+
+
+ MESSAGECACHE* lCache = mail_elt(lSource, aMessageNumber);
+
+ if (lCache->seen == 1) {
+ aFlagsVector[0] = 1;
+ }
+ if (lCache->deleted == 1) {
+ aFlagsVector[1] = 1;
+ }
+ if (lCache->flagged == 1) {
+ aFlagsVector[2] = 1;
+ }
+ if (lCache->answered == 1) {
+ aFlagsVector[3] = 1;
+ }
+ if (lCache->draft == 1) {
+ aFlagsVector[4] = 1;
+ }
+
+ return lResult;
+
+ }
+
+std::string
+ImapClient::fetchSubject(
+ const std::string& aHost,
+ const std::string& aUserName,
+ const std::string& aPassword,
+ const std::string& aMailbox,
+ const unsigned long aMessageNumber)
+{
+#include "linkage.c"
+
+ std::string lHost = "{" + aHost + "}" + aMailbox;
+ MAILSTREAM* lSource = getMailStream(aHost, aUserName, aPassword, aMailbox, true);
+
+ char lResult[256];
+ mail_fetchsubject(lResult, lSource, aMessageNumber, (unsigned long)255);
+ return std::string(lResult);
+}
+
+
+
+ std::string
+ ImapClient::fetchFrom(const std::string& aHost,
+ const std::string& aUserName,
+ const std::string& aPassword,
+ const std::string& aMailbox,
+ const unsigned long aMessageNumber) {
+
+#include "linkage.c"
+
+ MAILSTREAM* lSource = getMailStream(aHost, aUserName, aPassword, aMailbox, true);
+
+ char lResult[256];
+ mail_fetchsubject(lResult, lSource, aMessageNumber, (unsigned long)255);
+ return std::string(lResult);
+ }
+
+ long
+ ImapClient::convertNumber(const std::string& aHost,
+ const std::string& aUserName,
+ const std::string& aPassword,
+ const std::string& aMailbox,
+ const unsigned long aMessageNumber,
+ const bool aUid) {
+
+#include "linkage.c"
+
+ MAILSTREAM* lSource = getMailStream(aHost, aUserName, aPassword, aMailbox, true);
+
+ if (aUid) {
+ return mail_uid(lSource, aMessageNumber);
+ } else {
+ return mail_msgno(lSource, aMessageNumber);
+ }
+
+
+ }
+
+ ENVELOPE*
+ ImapClient::fetchStructure(const std::string& aHost,
+ const std::string& aUserName,
+ const std::string& aPassword,
+ const std::string& aMailbox,
+ BODY** aBody,
+ unsigned long aMessageNumber,
+ bool aUid,
+ std::vector<int>& aFlagsVector)
+ {
+#include "linkage.c"
+ *aBody = mail_newbody();
+ MAILSTREAM* lSource = getMailStream(aHost, aUserName, aPassword, aMailbox, true);
+
+ ENVELOPE * lResult = mail_fetchstructure_full (lSource, aMessageNumber, aBody, (aUid ? FT_UID : NIL));
+
+ if (!lResult) {
+ throw EmailException("WRONG_ID", "Could not get message - wrong message id.");
+ }
+
+ if (aUid) {
+ aMessageNumber = mail_msgno(lSource, aMessageNumber);
+ }
+
+ MESSAGECACHE* lCache = mail_elt(lSource, aMessageNumber);
+
+ if (lCache->seen == 1) {
+ aFlagsVector[0] = 1;
+ }
+ if (lCache->deleted == 1) {
+ aFlagsVector[1] = 1;
+ }
+ if (lCache->flagged == 1) {
+ aFlagsVector[2] = 1;
+ }
+ if (lCache->answered == 1) {
+ aFlagsVector[3] = 1;
+ }
+ if (lCache->draft == 1) {
+ aFlagsVector[4] = 1;
+ }
+
+ return lResult;
+
+ }
+
+ std::string
+ ImapClient::fetchText(const std::string& aHost,
+ const std::string& aUserName,
+ const std::string& aPassword,
+ const std::string& aMailbox,
+ unsigned long aMessageNumber,
+ bool aUid)
+ {
+#include "linkage.c"
+
+ MAILSTREAM* lSource = getMailStream(aHost, aUserName, aPassword, aMailbox, true);
+ unsigned long lLenght;
+ return std::string(mail_fetchtext_full(lSource, aMessageNumber, &lLenght, (aUid ? FT_UID : NIL)));
+ }
+
+
+ void
+ ImapClient::fetchFlags(const std::string& aHost,
+ const std::string& aUserName,
+ const std::string& aPassword,
+ const std::string& aMailbox,
+ unsigned long aMessageNumber,
+ std::vector<int>& aFlagsVector,
+ const bool aUid) {
+
+#include "linkage.c"
+
+
+ MAILSTREAM* lSource = getMailStream(aHost, aUserName, aPassword, aMailbox, true);
+ // convert aMessageNumber to message sequence number if necessary
+ std::string lSequenceNumber;
+ std::stringstream lConverter;
+ lConverter << aMessageNumber;
+ lConverter >> lSequenceNumber;
+ char* lSequence = const_cast<char*>(lSequenceNumber.c_str());
+
+
+
+ // update cache for this message (could have changed because of a call to setFlags)
+ mail_fetchflags_full(lSource, lSequence, (aUid ? FT_UID : NIL));
+
+ if (aUid) {
+ aMessageNumber = mail_msgno(lSource, aMessageNumber);
+ }
+
+ MESSAGECACHE* lCache = mail_elt(lSource, aMessageNumber);
+
+ if (lCache->seen == 1) {
+ aFlagsVector[0] = 1;
+ }
+ if (lCache->deleted == 1) {
+ aFlagsVector[1] = 1;
+ }
+ if (lCache->flagged == 1) {
+ aFlagsVector[2] = 1;
+ }
+ if (lCache->answered == 1) {
+ aFlagsVector[3] = 1;
+ }
+ if (lCache->draft == 1) {
+ aFlagsVector[4] = 1;
+ }
+
+ }
+
+ void
+ ImapClient::setFlags(const std::string& aHost,
+ const std::string& aUserName,
+ const std::string& aPassword,
+ const std::string& aMailbox,
+ const unsigned long aMessageNumber,
+ const std::vector<int>& aFlagsVector,
+ const bool aUid) {
+
+
+#include "linkage.c"
+ MAILSTREAM* lSource = getMailStream(aHost, aUserName, aPassword, aMailbox, true);
+ std::string lSequenceNumber;
+ std::stringstream lConverter;
+ lConverter << aMessageNumber;
+ lConverter >> lSequenceNumber;
+ char* lSequence = const_cast<char*>(lSequenceNumber.c_str());
+
+ if (aFlagsVector[0] == 1) {
+ mail_setflag_full(lSource, lSequence, "\\Seen", (aUid ? ST_UID : NIL) );
+ } else {
+ mail_clearflag_full(lSource, lSequence, "\\Seen", (aUid ? ST_UID : NIL ) );
+ }
+
+ if (aFlagsVector[1] == 1) {
+ mail_setflag_full(lSource, lSequence, "\\Deleted", (aUid ? ST_UID : NIL));
+ } else {
+ mail_clearflag_full(lSource, lSequence, "\\Deleted", (aUid ? ST_UID : NIL));
+ }
+ if (aFlagsVector[2] == 1) {
+ mail_setflag_full(lSource, lSequence, "\\Flagged", (aUid ? ST_UID : NIL));
+ } else {
+ mail_clearflag_full(lSource, lSequence, "\\Flagged", (aUid ? ST_UID : NIL));
+ }
+
+ if (aFlagsVector[3] == 1) {
+ mail_setflag_full(lSource, lSequence, "\\Answered", (aUid ? ST_UID : NIL));
+ } else {
+ mail_clearflag_full(lSource, lSequence, "\\Answered", (aUid ? ST_UID : NIL));
+ }
+ if (aFlagsVector[4] == 1) {
+ mail_setflag_full(lSource, lSequence, "\\Draft", (aUid ? ST_UID : NIL));
+ } else {
+ mail_clearflag_full(lSource, lSequence, "\\Draft", (aUid ? ST_UID : NIL));
+ }
+ }
+
+ std::string
+ ImapClient::fetchBodyFull(const std::string& aHost,
+ const std::string& aUserName,
+ const std::string& aPassword,
+ const std::string& aMailbox,
+ const unsigned long aMessageNumber,
+ const std::string& aSection,
+ const bool aUid)
+ {
+#include "linkage.c"
+ MAILSTREAM* lSource = getMailStream(aHost, aUserName, aPassword, aMailbox, true);
+ unsigned long lLenght;
+ // convert section int into char
+ return std::string(mail_fetchbody_full(lSource, aMessageNumber, const_cast<char*>(aSection.c_str()), &lLenght, (aUid ? FT_UID : NIL)));
+
+ }
+
+ SEARCHPGM*
+ ImapClient::search_criteria(std::vector<std::string> aCriteria) {
+ SEARCHPGM *lSearchProgram = NIL;
+
+ /* initializing the search program */
+ lSearchProgram= mail_newsearchpgm ();
+
+ /* Now, we iterate through the whole vector containing the search critera, building our search program */
+ for (std::vector<std::string>::iterator lIterator = aCriteria.begin(); lIterator != aCriteria.end(); ++lIterator) {
+ if (*lIterator == "ALL") {
+ /* do nothing ... */
+ } else if (*lIterator == "ANSWERED") {
+ lSearchProgram->answered = T;
+ } else if (*lIterator == "BCC") {
+ char * lNext = getNextStringAsChar(++lIterator);
+ mail_criteria_string (&lSearchProgram->bcc, &lNext);
+ } else if (*lIterator == "BEFORE") {
+ char* lNext = getNextStringAsChar(++lIterator);
+ mail_criteria_date(&lSearchProgram->before, &lNext);
+ } else if (*lIterator == "BODY") {
+ char* lNext = getNextStringAsChar(++lIterator);
+ mail_criteria_string(&lSearchProgram->body, &lNext);
+ } else if (*lIterator == "CC") {
+ char* lNext = getNextStringAsChar(++lIterator);
+ mail_criteria_string(&lSearchProgram->cc, &lNext);
+ } else if (*lIterator == "DELETED") {
+ lSearchProgram->deleted = T;
+ } else if (*lIterator == "DRAFT") {
+ lSearchProgram->draft = T;
+ } else if (*lIterator == "FLAGGED") {
+ lSearchProgram->flagged = T;
+ } else if (*lIterator == "FROM") {
+ char* lNext = getNextStringAsChar(++lIterator);
+ mail_criteria_string(&lSearchProgram->from, &lNext);
+ } else if (*lIterator == "HEADER") {
+ char *lHeaderField = getNextStringAsChar(++lIterator);
+ char *lHeaderContent = getNextStringAsChar(++lIterator);
+ SEARCHHEADER* lSearchHeader = mail_newsearchheader(lHeaderField, lHeaderContent);
+ if (lSearchProgram->header) {
+ lSearchProgram->header->next = lSearchHeader;
+ } else {
+ lSearchProgram->header = lSearchHeader;
+ }
+ } else if (*lIterator == "KEYWORD") {
+ char * lNext = getNextStringAsChar(++lIterator);
+ mail_criteria_string(&lSearchProgram->keyword, &lNext);
+ } else if (*lIterator == "LARGER") {
+ lIterator++;
+ // get the unsigned long value that should follow the Keyword LARGER
+ std::stringstream lLargerValueStream;
+ lLargerValueStream << (*lIterator).c_str();
+ unsigned long lLargerValue;
+ lLargerValueStream >> lLargerValue;
+ lSearchProgram->larger = lLargerValue;
+ } else if (*lIterator == "NEW") {
+ // according to the specification, this is equivalent to recent unseen
+ lSearchProgram->recent = T;
+ lSearchProgram->unseen = T;
+ } else if (*lIterator == "OLD") {
+ lSearchProgram->old = T;
+ } else if (*lIterator == "ON") {
+ char * lNext = getNextStringAsChar(++lIterator);
+ mail_criteria_date(&lSearchProgram->on, &lNext);
+ } else if (*lIterator == "RECENT") {
+ lSearchProgram->recent = T;
+ } else if (*lIterator == "SEEN") {
+ lSearchProgram->seen = T;
+ } else if (*lIterator == "SENTBEFORE") {
+ char * lNext = getNextStringAsChar(++lIterator);
+ mail_criteria_date(&lSearchProgram->sentbefore, &lNext);
+ } else if (*lIterator == "SENTON") {
+ char *lNext = getNextStringAsChar(lIterator);
+ mail_criteria_date(&lSearchProgram->senton, &lNext);
+ } else if (*lIterator == "SENTSINCE") {
+ char *lNext = getNextStringAsChar(++lIterator);
+ mail_criteria_date(&lSearchProgram->sentsince, &lNext);
+ } else if (*lIterator == "SMALLER") {
+ lIterator++;
+ std::stringstream lSmallerValueStream;
+ lSmallerValueStream << (*lIterator).c_str();
+ unsigned long lSmallerValue;
+ lSmallerValueStream >> lSmallerValue;
+ lSearchProgram->smaller = lSmallerValue;
+ } else if (*lIterator == "SUBJECT") {
+ char *lNext = getNextStringAsChar(++lIterator);
+ mail_criteria_string(&lSearchProgram->subject, &lNext);
+ } else if (*lIterator == "TEXT") {
+ char *lNext = getNextStringAsChar(++lIterator);
+ mail_criteria_string(&lSearchProgram->text, &lNext);
+ } else if (*lIterator == "TO") {
+ char *lNext = getNextStringAsChar(++lIterator);
+ mail_criteria_string(&lSearchProgram->to, &lNext);
+ } else if (*lIterator == "UNANSWERED") {
+ lSearchProgram->unanswered = T;
+ } else if (*lIterator == "UNDELETED") {
+ lSearchProgram->undeleted = T;
+ } else if (*lIterator == "UNDRAFT") {
+ lSearchProgram->undraft = T;
+ } else if (*lIterator == "UNFLAGGED") {
+ lSearchProgram->unflagged = T;
+ } else if (*lIterator == "UNKEYWORD") {
+ char *lNext = getNextStringAsChar(++lIterator);
+ mail_criteria_string(&lSearchProgram->unkeyword, &lNext);
+ } else if (*lIterator == "UNSEEN") {
+ lSearchProgram->unseen = T;
+ } else if (*lIterator == "NOT") {
+ std::vector<std::string> lNotVector;
+ std::string lNextWord = *(++lIterator);
+ // if next word is a keyword that needs a parameter
+ lNotVector.push_back(lNextWord);
+ if (!isSingleKeyword(lNextWord)) {
+ // pass parameter
+ lNotVector.push_back(*(++lIterator));
+ }
+ SEARCHPGM* lNotted = search_criteria(lNotVector);
+ SEARCHPGMLIST* lNotList = mail_newsearchpgmlist ();
+ lNotList->pgm = lNotted;
+ lSearchProgram->not = lNotList;
+ } else if (*lIterator == "OR") {
+ // Make all up to the or be the first search_program, then or the rest ...
+
+ std::vector<std::string> lOrVector(++lIterator, aCriteria.end());
+ SEARCHPGM* lOredProgram = search_criteria(lOrVector);
+
+ // or the search_program we have constructed so far with the search_program constructed from the rest of the strings
+ SEARCHOR* lOr = mail_newsearchor();
+ lOr->first = lOredProgram;
+ lOr->second = lSearchProgram;
+
+ // Make a new search program that only contains the OR'ed search_programs and assign the pointer we are going to return to it
+ SEARCHPGM* lNewSearchProgramm = mail_newsearchpgm();
+ lNewSearchProgramm->or = lOr;
+ lSearchProgram = lNewSearchProgramm;
+ // stop here, at least for the left-hand part of the OR.
+ break;
+
+ } else {
+ std::string lError = "Unknown keyword in IMAP search: " + *lIterator;
+ // if the word is not known ... throw an error through mm_log
+ mm_log((char *) lError.c_str(), ERROR);
+ }
+ }
+ return lSearchProgram;
+ }
+
+ char * ImapClient::getNextStringAsChar(std::vector<std::string>::iterator aIterator) {
+ return (char*) (*aIterator).c_str();
+ }
+
+ bool
+ ImapClient::isSingleKeyword(const std::string& aKey) {
+ if (aKey == "UNSEEN" || aKey == "UNANSWERED" || aKey == "UNDELETED" || aKey == "UNDRAFT" || aKey == "UNFLAGGED" || aKey == "DELETED" || aKey == "DRAFT" ||
+ aKey == "FLAGGED" || aKey == "NEW" || aKey == "OLD" || aKey == "RECENT" || aKey == "SEEN" || aKey == "ANSWERED") {
+ return true;
+ }
+ return false;
+ }
+
+ void
+ ImapClient::setStatus(unsigned long aMessages, unsigned long aRecent, unsigned long aUnseen, unsigned long aUIDNext, unsigned long aUIDValidity) {
+ theMessages = aMessages;
+ theRecent = aRecent;
+ theUnseen = aUnseen;
+ theUIDNext = aUIDNext;
+ theUIDValidity = aUIDValidity;
+ }
+
+
+ void
+ ImapClient::getStatus(unsigned long* aMessages, unsigned long* aRecent, unsigned long* aUnseen, unsigned long* aUIDNext, unsigned long* aUIDValidity) {
+
+ *aMessages = theMessages;
+ *aRecent = theRecent;
+ *aUnseen = theUnseen;
+ *aUIDNext = theUIDNext;
+ *aUIDValidity = theUIDValidity;
+
+
+ }
+
+ void
+ ImapClient::addListedMailbox(const std::string& aListedMail) {
+ theListedMailboxes.push_back(aListedMail);
+ }
+
+
+ std::string
+ ImapClient::getError() {
+ // will not see an old error
+
+ std::string lTempError(theErrorMessage.str());
+ theErrorMessage.clear();
+ return lTempError;
+ }
+
+
+
+ void
+ ImapClient::addError(const std::string& aMessage) {
+ theErrorMessage << aMessage << std::endl;
+ }
+
+ void ImapClient::addLogEntry(std::string const &aLogEntry)
+ {
+ theLog << aLogEntry << std::endl;
+ }
+
+ void
+ ImapClient::addFoundSequenceNumber(long aSequenceNumber) {
+ theFoundSequenceNumbers.push_back(aSequenceNumber);
+ }
+
+ void
+ ImapClient::checkMailStream(MAILSTREAM *aStream)
+ {
+ if (!aStream) {
+ std::stringstream lMessage;
+ lMessage << "Could not open mail stream. " << theErrorMessage.str() << "." << std::endl;
+ theLog.clear();
+ theErrorMessage.clear();
+ throw EmailException("CONNECTION_ERROR", lMessage.str());
+ }
+ }
+
+
+} /* emailmodule */ } /* zorba */
+
+
+
+void mm_searched (MAILSTREAM *stream,unsigned long msgno) {
+ zorba::emailmodule::ImapClient::Instance().addFoundSequenceNumber(msgno);
+}
+void mm_exists (MAILSTREAM *stream,unsigned long number) {}
+void mm_expunged (MAILSTREAM *stream,unsigned long number) {}
+
+/*
+ * Callback for when mail_fetchflags(_full) is called.
+ */
+void mm_flags (MAILSTREAM *stream,unsigned long number) {
+}
+
+/* Callback for when mail_list or mail_listsub are called ... */
+void mm_list (MAILSTREAM *stream,int delimiter,char *mailbox, long attributes) {
+ if (!(attributes & LATT_NOSELECT) && *mailbox) {
+ zorba::emailmodule::ImapClient::Instance().addListedMailbox(std::string(mailbox));
+ }
+}
+void mm_lsub (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes) {
+ if (!(attributes & LATT_NOSELECT) && *mailbox) {
+ zorba::emailmodule::ImapClient::Instance().addListedMailbox(std::string(mailbox));
+ }
+}
+
+void mm_critical (MAILSTREAM *stream) {}
+void mm_nocritical (MAILSTREAM *stream) {}
+long mm_diskerror (MAILSTREAM *stream,long errcode,long serious) {return NIL;}
+
+
+void mm_notify (MAILSTREAM *stream,char *string,long errflg) {}
+
+
+
+void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status) {
+ zorba::emailmodule::ImapClient::Instance().setStatus(status->messages, status->recent, status->unseen, status->uidnext, status->uidvalidity);
+}
+
+/* Log an event for the user to see
+ * Accepts: string to log
+ * error flag
+ */
+void mm_log (char *string,long errflg)
+{
+
+ switch ((short) errflg) {
+ case NIL:
+
+ case PARSE:
+ case WARN:
+ zorba::emailmodule::ImapClient::Instance().addLogEntry(string);
+ break;
+ case ERROR:
+ zorba::emailmodule::ImapClient::Instance().addError(string);
+ break;
+ }
+}
+
+/* Log an event to debugging telemetry
+ * Accepts: string to log
+ */
+void mm_dlog (char *string)
+{
+ std::cout << string << '\n';
+}
+
+/* Get user name and password for this host
+ * Accepts: parse of network mailbox name
+ * where to return user name
+ * where to return password
+ * trial count
+ */
+void mm_login (NETMBX *mb,char *user,char *pwd,long trial)
+{
+ std::string lUser = zorba::emailmodule::ImapClient::Instance().getUserName().c_str();
+ std::string lPassword = zorba::emailmodule::ImapClient::Instance().getPassword().c_str();
+
+ strcpy(user, const_cast<char*>(lUser.c_str()));
+ strcpy(pwd, const_cast<char*>(lPassword.c_str()));
+}
+
+/* Log a fatal error event
+ * Accepts: string to log
+ */
+void mm_fatal (char *string)
+{
+ printf ("?%s\n",string);
+}
+
+
+#ifndef WIN32
+#pragma GCC diagnostic warning "-Wwrite-strings"
+#endif
=== added file 'src/com/zorba-xquery/www/modules/email/cclient/imap_client.h'
--- src/com/zorba-xquery/www/modules/email/cclient/imap_client.h 1970-01-01 00:00:00 +0000
+++ src/com/zorba-xquery/www/modules/email/cclient/imap_client.h 2014-04-30 23:07:12 +0000
@@ -0,0 +1,294 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ZORBA_EMAIL_IMAP_CLIENT_H
+#define ZORBA_EMAIL_IMAP_CLIENT_H
+
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <c-client.h>
+#undef max
+
+#include <string>
+#include <list>
+#include <vector>
+#include <exception>
+#include <sstream>
+
+
+namespace zorba { namespace emailmodule {
+
+ class ImapClient
+ {
+ public:
+ static ImapClient& Instance()
+ {
+ static ImapClient lInstance;
+ return lInstance;
+ }
+
+
+
+ bool
+ send(const std::string& aHost,
+ const std::string& aUsername,
+ const std::string& aPassword,
+ ENVELOPE* aEnvelope,
+ BODY* aBody,
+ std::stringstream& aDiagnostics);
+
+
+
+ MAILSTREAM* getMailStream(const std::string& aHost,
+ const std::string& aUsername,
+ const std::string& aPassword,
+ const std::string& aMailbox,
+ const bool aFullOpen);
+
+
+ void status(const std::string& aHost,
+ const std::string& aUsername,
+ const std::string& aPassword,
+ const std::string& aMailbox);
+
+ bool create(const std::string& aHost,
+ const std::string& aUsername,
+ const std::string& aPassword,
+ const std::string& aMailboxName);
+
+ bool delete_mailbox(const std::string& aHost,
+ const std::string& aUsername,
+ const std::string& aPassword,
+ const std::string& aMailboxName);
+
+ bool rename(const std::string& aHost,
+ const std::string& aUserName,
+ const std::string& aPassword,
+ const std::string& aMailboxFromName,
+ const std::string& aMailboxToName);
+
+ bool subscription(const std::string& aHost,
+ const std::string& aUserName,
+ const std::string& aPassword,
+ const std::string& aMailbox,
+ bool subscribe);
+
+ bool expunge(const std::string& aHost,
+ const std::string& aUserName,
+ const std::string& aPassword,
+ const std::string& aMailbox);
+
+ bool copy(const std::string& aHost,
+ const std::string& aUserName,
+ const std::string& aPassword,
+ const std::string& aMailboxFrom,
+ const std::string& aMailboxTo,
+ const std::string& aMessageNumbers,
+ bool aUid,
+ bool aCopy);
+
+
+
+ std::vector<std::string> list(const std::string& aHost,
+ const std::string& aUserName,
+ const std::string& aPassword,
+ const std::string& aReferencePath,
+ const std::string& aPattern,
+ bool aOnlySuscribed);
+
+ std::vector<long> search(const std::string& aHost,
+ const std::string& aUserName,
+ const std::string& aPassword,
+ const std::string& aMailbox,
+ const std::string& aCriteria,
+ bool aUid);
+
+ ENVELOPE* fetchEnvelope(const std::string& aHost,
+ const std::string& aUserName,
+ const std::string& aPassword,
+ const std::string& aMailbox,
+ unsigned long aMessageNumber,
+ std::vector<int>& aFlags,
+ const bool aUid);
+
+ ENVELOPE* fetchStructure(const std::string& aHost,
+ const std::string& aUserName,
+ const std::string& aPassword,
+ const std::string& aMailbox,
+ BODY** aBody,
+ unsigned long aMessageNumber,
+ bool aUid,
+ std::vector<int>& aFlags);
+
+ std::string fetchText(const std::string& aHost,
+ const std::string& aUserName,
+ const std::string& aPassword,
+ const std::string& aMailbox,
+ unsigned long aMessgetNumber,
+ bool aUid);
+
+ void fetchFlags(const std::string& aHost,
+ const std::string& aUserName,
+ const std::string& aPassword,
+ const std::string& aMailbox,
+ unsigned long aMessageNumber,
+ std::vector<int>& aFlags,
+ const bool aUid);
+
+
+ void setFlags(const std::string& aHost,
+ const std::string& aUserName,
+ const std::string& aPassword,
+ const std::string& aMailbox,
+ const unsigned long aMessageNumber,
+ const std::vector<int>& aFlagsVector,
+ const bool aUid);
+
+
+
+ std::string
+ fetchBodyFull(const std::string& aHost,
+ const std::string& aUserName,
+ const std::string& aPassword,
+ const std::string& aMailbox,
+ const unsigned long aMessageNumber,
+ const std::string& aSection,
+ const bool aUid);
+
+
+ std::string
+ fetchSubject(const std::string& aHost,
+ const std::string& aUserName,
+ const std::string& aPassword,
+ const std::string& aMailbox,
+ const unsigned long aMessageNumber);
+
+ std::string
+ fetchFrom(const std::string& aHost,
+ const std::string& aUserName,
+ const std::string& aPassword,
+ const std::string& aMailbox,
+ const unsigned long aMessageNumber);
+
+
+ long
+ convertNumber(const std::string& aHost,
+ const std::string& aUserName,
+ const std::string& aPassword,
+ const std::string& aMailbox,
+ const unsigned long aMessageNumber,
+ const bool aUid);
+
+ /*
+ * Generates a search_program out of an IMAP_rv4 complient vector of strings.
+ * The search program is then used by the mail_search_full function which hasn't got a built in parser.
+ */
+ SEARCHPGM *search_criteria(std::vector<std::string> aCriteria);
+
+ /*
+ * Returns the next string of this iterator as char *.
+ */
+ char * getNextStringAsChar(std::vector<std::string>::iterator aIterator);
+
+ /*
+ * Returns true if the passed keyword does not need an argument (according to the IMAP_rv4 search syntax.
+ */
+ bool isSingleKeyword(const std::string& aKeyword);
+
+
+ void setUserName(const std::string& aUserName);
+ void setPassword(const std::string& aPassword);
+
+ std::string getUserName();
+ std::string getPassword();
+ std::string getError();
+ void addError(const std::string& aError);
+
+ void addLogEntry(const std::string& aLogEntry);
+
+ void setStatus(unsigned long aMessages, unsigned long aRecent, unsigned long aUnseen, unsigned long aUIDNext, unsigned long aUIDValidity);
+
+ void getStatus(unsigned long* aMessages, unsigned long* aRecent, unsigned long* aUnseen, unsigned long* aUIDNextm, unsigned long* aUIDValidity);
+
+ void addFoundSequenceNumber(long aSequenceNumber);
+
+
+ void addListedMailbox(const std::string& aListedMail);
+
+
+ private:
+ //ctor, dtor, copy ctor are all hidden
+ ImapClient() {
+ theFlags.assign(6, 0);
+ };
+ ~ImapClient() {
+ // make sure that theMailstream is not open!
+ if (theHosts.size() > 0) {
+ std::list<Host>::iterator allHostsIterator;
+ for (allHostsIterator = theHosts.begin(); allHostsIterator != theHosts.end(); allHostsIterator++) {
+ MAILSTREAM * lToClose = (*allHostsIterator).lMailStream;
+ if (lToClose) {
+ mail_close(lToClose);
+ }
+ }
+ }
+ };
+
+ void
+ checkMailStream(MAILSTREAM* aStream);
+
+ struct Host {
+ MAILSTREAM * lMailStream;
+ std::string lHostNameWithMailbox;
+ std::string lUsername;
+ std::string lPassword;
+ bool lIsFullOpen;
+
+ };
+
+ ImapClient(ImapClient const&) {};
+ std::list<Host> theHosts;
+ // the current mailstream, in future versions this could be a mailstream pool ...
+
+ // the Host of the current mailstream
+
+ // string containing error message
+ std::stringstream theErrorMessage;
+ std::stringstream theLog;
+ std::string theUserName;
+ std::string thePassword;
+
+ // vars for status
+ unsigned long theMessages;
+ unsigned long theRecent;
+ unsigned long theUnseen;
+ unsigned long theUIDNext;
+ unsigned long theUIDValidity;
+ std::vector<std::string> theListedMailboxes;
+ std::vector<long> theFoundSequenceNumbers;
+ std::vector<int> theFlags;
+ };
+
+ }//namespace email
+}//namespace zorba
+
+#endif // ZORBA_MODULES_EMAIL_UW_IMAP_H
+
+
+
=== added file 'src/com/zorba-xquery/www/modules/email/email.xsd'
--- src/com/zorba-xquery/www/modules/email/email.xsd 1970-01-01 00:00:00 +0000
+++ src/com/zorba-xquery/www/modules/email/email.xsd 2014-04-30 23:07:12 +0000
@@ -0,0 +1,174 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<schema xmlns="http://www.w3.org/2001/XMLSchema";
+ targetNamespace="http://www.zorba-xquery.com/modules/email";
+ xmlns:tns="http://www.zorba-xquery.com/modules/email";
+ elementFormDefault="qualified">
+<!--
+:: Copyright 2006-2008 The FLWOR Foundation.
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+::
+:: http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+::
+-->
+
+ <annotation>
+ <documentation xml:lang="en">
+ This schema defines the types used by the Zorba XQuery IMAP and SMTP modules.
+ </documentation>
+ </annotation>
+
+ <complexType name="mailboxType">
+ <sequence>
+ <element name="hostName" type="string"/>
+ <element name="mailboxName" type="string"/>
+ </sequence>
+ </complexType>
+
+ <complexType name="hostInfoType">
+ <sequence>
+ <element name="hostName" type="string"/>
+ <element name="userName" type="string"/>
+ <element name="password" type="string"/>
+ </sequence>
+ </complexType>
+
+ <complexType name="statusType">
+ <sequence>
+ <element name="messages" type="long"/>
+ <element name="recent" type="long"/>
+ <element name="unseen" type="long"/>
+ <element name="uidnext" type="long"/>
+ <element name="uidvalidity" type="long"/>
+ </sequence>
+ </complexType>
+
+ <element name="mailbox" type="tns:mailboxType"/>
+ <element name="status" type="tns:statusType"/>
+ <element name="hostInfo" type="tns:hostInfoType"/>
+
+ <complexType name="emptyType">
+ <complexContent>
+ <restriction base="anyType"/>
+ </complexContent>
+ </complexType>
+
+ <complexType name="flagsType">
+ <all>
+ <element name="seen" type="tns:emptyType" maxOccurs="1" minOccurs="0"/>
+ <element name="deleted" type="tns:emptyType" maxOccurs="1" minOccurs="0"/>
+ <element name="flagged" type="tns:emptyType" maxOccurs="1" minOccurs="0"/>
+ <element name="answered" type="tns:emptyType" maxOccurs="1" minOccurs="0" />
+ <element name="draft" type="tns:emptyType" maxOccurs="1" minOccurs="0"/>
+ </all>
+ </complexType>
+
+ <element name="flags" type="tns:flagsType"/>
+
+ <simpleType name="emailAddressType">
+ <restriction base="string">
+ <pattern value="[^@]+@[^\.]+\..+"/>
+ </restriction>
+ </simpleType>
+
+ <complexType name="emailAddress">
+ <sequence>
+ <element name="name" type="string" maxOccurs="1" minOccurs="0"/>
+ <element name="email" type="tns:emailAddressType" maxOccurs="1" minOccurs="1"/>
+ </sequence>
+ </complexType>
+
+ <complexType name="recipientType">
+ <sequence>
+ <choice>
+ <element name="to" type="tns:emailAddress"/>
+ <element name="cc" type="tns:emailAddress"/>
+ <element name="bcc" type="tns:emailAddress"/>
+ </choice>
+ </sequence>
+ </complexType>
+
+ <complexType name="envelopeType">
+ <sequence>
+ <element name="remail" type="string" maxOccurs="1" minOccurs="0"/>
+ <element name="date" type="dateTime" maxOccurs="1" minOccurs="0"/>
+ <element name="from" type="tns:emailAddress" maxOccurs="1" minOccurs="0"/>
+ <element name="sender" type="tns:emailAddress" maxOccurs="1" minOccurs="0"/>
+ <element name="replyTo" type="tns:emailAddress" maxOccurs="1" minOccurs="0"/>
+ <element name="subject" type="string" maxOccurs="1" minOccurs="0"/>
+ <element name="recipient" type="tns:recipientType" maxOccurs="unbounded" minOccurs="0"/>
+ <element name="messageId" type="string" maxOccurs="1" minOccurs="0"/>
+ <element name="flags" type="tns:flagsType" maxOccurs="1" minOccurs="0"/>
+ </sequence>
+ </complexType>
+
+ <complexType name="messageType">
+ <sequence>
+ <element name="envelope" type="tns:envelopeType" maxOccurs="1" minOccurs="0"/>
+ <element name="mimeVersion" type="string" maxOccurs="1" minOccurs="0" default="1.0"/>
+ <element name="body" type="tns:bodyTypeChoice" maxOccurs="1" minOccurs="1"/>
+ </sequence>
+ </complexType>
+
+ <element name="message" type="tns:messageType"/>
+
+ <element name="envelope" type="tns:envelopeType"/>
+
+ <!-- mime definitions -->
+
+ <!-- definition of simple elements -->
+ <simpleType name="contentTypeValue">
+ <restriction base="string">
+ <pattern value="[a-zA-Z]+/[a-zA-Z0-9\-\+\.]+"/>
+ </restriction>
+ </simpleType>
+
+ <simpleType name="cteType">
+ <restriction base="string">
+ <pattern value="ENC7BIT|ENC8BIT|ENCBINARY|ENCBASE64|ENCQUOTEDPRINTABLE|ENCOTHER"/>
+ </restriction>
+ </simpleType>
+
+ <complexType name="contentType">
+ <simpleContent>
+ <extension base="string">
+ <attribute name="contentType" type="tns:contentTypeValue"/>
+ <attribute name="charset" type="string" default="us-ascii"/>
+ <attribute name="contentTransferEncoding" type="tns:cteType" default="ENC7BIT"/>
+ <attribute name="contentDisposition" type="string"/>
+ <attribute name="contentDisposition-filename" type="string"/>
+ <attribute name="contentDisposition-modification-date" type="dateTime"/>
+ <attribute name="content-id" type="string"/>
+ </extension>
+ </simpleContent>
+ </complexType>
+
+ <complexType name="multipartType">
+ <choice maxOccurs="unbounded">
+ <element name="content" type="tns:contentType" minOccurs="1"/>
+ <element name="multipart" type="tns:multipartType" minOccurs="1"/>
+ </choice>
+ <attribute name="contentType" type="tns:contentTypeValue"/>
+ <attribute name="charset" type="string" default="us-ascii"/>
+ <attribute name="contentTransferEncoding" type="tns:cteType" default="ENC7BIT"/>
+ <attribute name="contentDisposition" type="string"/>
+ </complexType>
+
+ <complexType name="bodyTypeChoice">
+ <sequence>
+ <choice>
+ <element name="content" type="tns:contentType" maxOccurs="1" minOccurs="1"/>
+ <element name="multipart" type="tns:multipartType" minOccurs="1" maxOccurs="1"/>
+ </choice>
+ </sequence>
+ </complexType>
+
+ </schema>
=== added file 'src/com/zorba-xquery/www/modules/email/imap.xq'
--- src/com/zorba-xquery/www/modules/email/imap.xq 1970-01-01 00:00:00 +0000
+++ src/com/zorba-xquery/www/modules/email/imap.xq 2014-04-30 23:07:12 +0000
@@ -0,0 +1,627 @@
+xquery version "3.0";
+
+(:
+ : Copyright 2006-2009 The FLWOR Foundation.
+ :
+ : Licensed under the Apache License, Version 2.0 (the "License");
+ : you may not use this file except in compliance with the License.
+ : You may obtain a copy of the License at
+ :
+ : http://www.apache.org/licenses/LICENSE-2.0
+ :
+ : Unless required by applicable law or agreed to in writing, software
+ : distributed under the License is distributed on an "AS IS" BASIS,
+ : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ : See the License for the specific language governing permissions and
+ : limitations under the License.
+:)
+
+(:~
+ : This module provides functions for accessing and manipulating emails on mail
+ : servers through the IMAP protocol.
+ :
+ : All functions in this module receive as the first argument the IMAP host and user
+ : information. This is an element with the type <code>hostInfoType</code> as defined
+ : in the email schema: <code>http://www.zorba-xquery.com/modules/email</code>.
+ :
+ : For example:
+ : <pre class="ace-static" ace-mode="xquery"><![CDATA[
+ : <email:hostInfo>
+ : <email:hostName>imap.example.com</email:hostName>
+ : <email:userName>myuser</email:userName>
+ : <email:password>mypassword</email:password>
+ : </email:hostInfo>
+ : ]]></pre>
+ :
+ : The <code>hostInfoType</code> only needs to be in the email schema namespace
+ : (<code>http://www.zorba-xquery.com/modules/email</code>). It does not need
+ : to be validated since it's validated by the module.
+ :
+ : @author Daniel Thomas, Gabriel Petrovay
+ : @see <a href="http://www.washington.edu/imap/";>c-client library part of UW IMAP toolkit</a>
+ : @library <a href="http://www.washington.edu/imap/";>c-client library part of UW IMAP toolkit</a>
+ : @project Zorba/Input Output/IMAP
+ :)
+module namespace imap = 'http://www.zorba-xquery.com/modules/email/imap';
+
+import schema namespace email = 'http://www.zorba-xquery.com/modules/email';
+
+declare namespace an = "http://zorba.io/annotations";;
+
+declare namespace ver = "http://zorba.io/options/versioning";;
+declare option ver:module-version "1.0";
+
+(:~
+ : Returns the status of the given mailbox.
+ :
+ : The status of a mailbox contains:
+ : <ul>
+ : <li><code>messages</code>: the number of messages in the mailbox</li>
+ : <li><code>recent</code>: the number of messages flagged as recent</li>
+ : <li><code>unseen</code>: the number of messages flagged as unseen</li>
+ : <li><code>uidnext</code>: the next unique identifier that will be assigned to a message</li>
+ : <li><code>uidvalidity</code>: a value that, together with the <code>uidnext</code> value
+ : forms a 64 bit number that must be unique for the server</li>
+ : </ul>
+ :
+ : @param $host-info The IMAP host, user name, and password.
+ : @param $mailbox The mailbox for which we want to have the status.
+ : @return The <code>status</code> of the specified <code>$mailbox</code>.
+ : The result is validated against the schema:
+ : <code>http://www.zorba-xquery.com/modules/email</code>.
+ : @error imap:IMAP0001 If the IMAP operation failed.
+ : @error imap:IMAP0002 If the connection to the IMAP server is refused.
+ : @error err:XQDY0027 If the value of <code>$host-info</code> is not valid
+ : according to the email schema:
+ : <code>http://www.zorba-xquery.com/modules/email</code>
+ : @example examples/Queries/imap/status_example.xq
+ :)
+declare %an:nondeterministic function imap:status(
+ $host-info as element(email:hostInfo),
+ $mailbox as xs:string)
+ as element(email:status)
+{
+ let $status := imap:status-impl(validate {$host-info}, $mailbox)
+ let $status-sequence := fn:tokenize($status, ',')
+ return
+ validate {
+ <email:status>
+ <email:messages>{$status-sequence[1]}</email:messages>
+ <email:recent>{$status-sequence[2]}</email:recent>
+ <email:unseen>{$status-sequence[3]}</email:unseen>
+ <email:uidnext>{$status-sequence[4]}</email:uidnext>
+ <email:uidvalidity>{$status-sequence[5]}</email:uidvalidity>
+ </email:status>
+ }
+};
+
+declare %private %an:nondeterministic function imap:status-impl($host-info as element(email:hostInfo), $mailbox as xs:string) as xs:string* external;
+
+(:~
+ : Creates a new mailbox for the given user.
+ :
+ : @param $host-info The IMAP host, user name, and password.
+ : @param $mailbox-name The name for the new mailbox.
+ : @return The function is declared as sequential and has side-effects. It returns the empty sequence.
+ : @error imap:IMAP0001 If the IMAP operation failed.
+ : @error imap:IMAP0002 If the connection to the IMAP server is refused.
+ : @error err:XQDY0027 If the value of <code>$host-info</code> is not valid
+ : according to the email schema:
+ : <code>http://www.zorba-xquery.com/modules/email</code>
+ : @example examples/Queries/imap/create_rename_delete_example.xq
+ :)
+declare %an:sequential function imap:create(
+ $host-info as element(email:hostInfo),
+ $mailbox-name as xs:string)
+ as empty-sequence()
+{
+ imap:create-impl(validate {$host-info}, $mailbox-name)
+};
+
+declare %private %an:sequential function imap:create-impl($host-info as element(email:hostInfo), $mailbox-name as xs:string) as empty-sequence() external;
+
+(:~
+ : Deletes a mailbox for the given user.
+ :
+ : @param $host-info The IMAP host, user name, and password.
+ : @param $mailbox-name The name of the mailbox to delete.
+ : @return The function is declared as sequential and has side-effects. It returns the empty sequence.
+ : @error imap:IMAP0001 If the IMAP operation failed.
+ : @error imap:IMAP0002 If the connection to the IMAP server is refused.
+ : @error err:XQDY0027 If the value of <code>$host-info</code> is not valid
+ : according to the email schema:
+ : <code>http://www.zorba-xquery.com/modules/email</code>
+ : @example examples/Queries/imap/create_rename_delete_example.xq
+ :)
+declare %an:sequential function imap:delete(
+ $host-info as element(email:hostInfo),
+ $mailbox-name as xs:string)
+ as empty-sequence()
+{
+ imap:delete-impl(validate {$host-info}, $mailbox-name)
+};
+
+declare %private %an:sequential function imap:delete-impl($host-info as element(email:hostInfo), $mailbox-name as xs:string) as empty-sequence() external;
+
+(:~
+ : Renames a mailbox.
+ :
+ : @param $host-info The IMAP host, user name, and password.
+ : @param $mailbox-old The name of the mailbox we want to rename.
+ : @param $mailbox-new The new name for the mailbox.
+ : @return The function is declared as sequential and has side-effects. It returns the empty sequence.
+ : @error imap:IMAP0001 If the IMAP operation failed.
+ : @error imap:IMAP0002 If the connection to the IMAP server is refused.
+ : @error err:XQDY0027 If the value of <code>$host-info</code> is not valid
+ : according to the email schema:
+ : <code>http://www.zorba-xquery.com/modules/email</code>
+ : @example examples/Queries/imap/create_rename_delete_example.xq
+ :)
+declare %an:sequential function imap:rename(
+ $host-info as element(email:hostInfo),
+ $mailbox-old as xs:string,
+ $mailbox-new as xs:string)
+ as empty-sequence()
+{
+ imap:rename-impl(validate {$host-info}, $mailbox-old, $mailbox-new)
+};
+
+declare %private %an:sequential function imap:rename-impl($host-info as element(email:hostInfo), $mailbox-old as xs:string, $mailbox-new as xs:string) as empty-sequence() external;
+
+(:~
+ : Lists IMAP folders for the specified user on the host that match the pattern.
+ :
+ : @param $host-info The IMAP host, user name, and password.
+ : @param $mailbox-ref is applied to pattern in an implementation dependent fashion to search for matching mailbox names.
+ : @param $pattern The pattern for mailboxes to look for (can include wildcards '*' and '%').
+ : @param $only-subscribed If set true, only mailboxes are listed to which the user is subscribed.
+ : @return A sequence of <code>mailbox</code> elements.
+ : The result elements are validated against the schema:
+ : <code>http://www.zorba-xquery.com/modules/email</code>.
+ : @error imap:IMAP0001 If the IMAP operation failed.
+ : @error imap:IMAP0002 If the connection to the IMAP server is refused.
+ : @error err:XQDY0027 If the value of <code>$host-info</code> is not valid
+ : according to the email schema:
+ : <code>http://www.zorba-xquery.com/modules/email</code>
+ : @example examples/Queries/imap/list_example.xq
+ :)
+declare %an:nondeterministic function imap:list(
+ $host-info as element(email:hostInfo),
+ $mailbox-ref as xs:string,
+ $pattern as xs:string,
+ $only-subscribed as xs:boolean)
+ as element(email:mailbox)*
+{
+ let $mailbox-sequence := imap:list-impl(validate {$host-info}, $mailbox-ref, $pattern, $only-subscribed)
+ for $mailbox in $mailbox-sequence
+ return
+ validate {
+ <email:mailbox>
+ <email:hostName>{$host-info/email:hostName/text()}</email:hostName>
+ <email:mailboxName>{fn:substring-after($mailbox, '}')}</email:mailboxName>
+ </email:mailbox>
+ }
+};
+
+declare %private %an:nondeterministic function imap:list-impl($host-info as element(email:hostInfo), $mailbox-ref as xs:string, $pattern as xs:string, $only-subscribed as xs:boolean) as xs:string* external;
+
+(:~
+ : Subscribes the user to the specified mailbox.
+ :
+ : @param $host-info The IMAP host, user name, and password.
+ : @param $mailbox The mailbox the user wants to subscribe to.
+ : @return The function is declared as sequential and has side-effects. It returns the empty sequence.
+ : @error imap:IMAP0001 If the IMAP operation failed.
+ : @error imap:IMAP0002 If the connection to the IMAP server is refused.
+ : @error err:XQDY0027 If the value of <code>$host-info</code> is not valid
+ : according to the email schema:
+ : <code>http://www.zorba-xquery.com/modules/email</code>
+ : @example examples/Queries/imap/subscribe_unsubscribe_example.xq
+ :)
+declare %an:sequential function imap:subscribe(
+ $host-info as element(email:hostInfo),
+ $mailbox as xs:string)
+ as empty-sequence()
+{
+ imap:subscribe-impl(validate {$host-info}, $mailbox)
+};
+
+declare %private %an:sequential function imap:subscribe-impl($host-info as element(email:hostInfo), $mailbox as xs:string) as empty-sequence() external;
+
+(:~
+ : Unsubscribes the user from the specified mailbox.
+ :
+ : @param $host-info The IMAP host, user name, and password.
+ : @param $mailbox The mailbox the user wants to unsubscribe from.
+ : @return The function is declared as sequential and has side-effects. It returns the empty sequence.
+ : @error imap:IMAP0001 If the IMAP operation failed.
+ : @error imap:IMAP0002 If the connection to the IMAP server is refused.
+ : @error err:XQDY0027 If the value of <code>$host-info</code> is not valid
+ : according to the email schema:
+ : <code>http://www.zorba-xquery.com/modules/email</code>
+ : @example examples/Queries/imap/subscribe_unsubscribe_example.xq
+ :)
+declare %an:sequential function imap:unsubscribe(
+ $host-info as element(email:hostInfo),
+ $mailbox as xs:string)
+ as empty-sequence()
+{
+ imap:unsubscribe-impl(validate {$host-info}, $mailbox)
+};
+
+declare %private %an:sequential function imap:unsubscribe-impl($host-info as element(email:hostInfo), $mailbox as xs:string) as empty-sequence() external;
+
+(:~
+ : Permanently deletes all messages of the given mailbox that have the "deleted" flag set.
+ :
+ : @param $host-info The IMAP host, user name, and password.
+ : @param $mailbox The mailbox for which all messages that have the \Deleted flag set should be permanently deleted.
+ : @return The function is declared as sequential and has side-effects. It returns the empty sequence.
+ : @error imap:IMAP0001 If the IMAP operation failed.
+ : @error imap:IMAP0002 If the connection to the IMAP server is refused.
+ : @error err:XQDY0027 If the value of <code>$host-info</code> is not valid
+ : according to the email schema:
+ : <code>http://www.zorba-xquery.com/modules/email</code>
+ : @example examples/Queries/imap/expunge_example.xq
+ :)
+declare %an:sequential function imap:expunge(
+ $host-info as element(email:hostInfo),
+ $mailbox as xs:string)
+ as empty-sequence()
+{
+ imap:expunge-impl(validate {$host-info}, $mailbox)
+};
+
+declare %private %an:sequential function imap:expunge-impl($host-info as element(email:hostInfo), $mailbox as xs:string) as empty-sequence() external;
+
+(:~
+ : Searches a mailbox for messages that match the given criteria.
+ : The criteria should be a string as defined in the RFC3501 (IMAP4rev1).
+ : A valid example would be: 'FROM zorba@xxxxxxxxx OR NOT SUBJECT Bug'.
+ : Depending on the value of <code>$uid</code>, the function will either
+ : return matching sequence numbers or unique identifiers.
+ :
+ : @param $host-info The IMAP host, user name, and password.
+ : @param $mailbox The mailbox to search.
+ : @param $criteria The searching criteria.
+ : @param $uid If true, the function returns the sequence of unique identifiers
+ : corresponding to the matching mails, else the corresponding sequence
+ : numbers are returned.
+ : @return Either the sequence of matching sequence numbers or the sequence of
+ : matching unique identifiers.
+ : @error imap:IMAP0001 If the IMAP operation failed.
+ : @error imap:IMAP0002 If the connection to the IMAP server is refused.
+ : @error err:XQDY0027 If the value of <code>$host-info</code> is not valid
+ : according to the email schema:
+ : <code>http://www.zorba-xquery.com/modules/email</code>
+ : @example examples/Queries/imap/search_example.xq
+ :)
+declare %an:nondeterministic function imap:search(
+ $host-info as element(email:hostInfo),
+ $mailbox as xs:string,
+ $criteria as xs:string,
+ $uid as xs:boolean?)
+ as xs:long*
+{
+ imap:search-impl(validate {$host-info}, $mailbox, $criteria, $uid)
+};
+
+declare %private %an:nondeterministic function imap:search-impl($host-info as element(email:hostInfo), $mailbox as xs:string, $criteria as xs:string, $uid as xs:boolean?) as xs:long* external;
+
+(:~
+ : Copies messages between mailboxes.
+ :
+ : Depending on the value of <code>$uid</code>, the messages are either specified
+ : through their sequence number or through their unique id. Both mailboxes must exist.
+ :
+ : @param $host-info The IMAP host, user name, and password.
+ : @param $mailbox-from The mailbox in which the messages reside.
+ : @param $mailbox-to The mailbox in to which the messages are copied.
+ : @param $messages The messages to be copied, specified either by their sequence number or their unique id.
+ : @param $uid If true, <code>$messages</code> are treated as sequence numbers. Else as unique identifiers.
+ : @return The function is declared as sequential and has side-effects. It returns the empty sequence.
+ : @error imap:IMAP0001 If the IMAP operation failed.
+ : @error imap:IMAP0002 If the connection to the IMAP server is refused.
+ : @error imap:IMAP0003 If no message is found with the provided sequence number/unique identifier.
+ : @error err:XQDY0027 If the value of <code>$host-info</code> is not valid
+ : according to the email schema:
+ : <code>http://www.zorba-xquery.com/modules/email</code>
+ : @example examples/Queries/imap/copy_example.xq
+ :)
+declare %an:sequential function imap:copy(
+ $host-info as element(email:hostInfo),
+ $mailbox-from as xs:string,
+ $mailbox-to as xs:string,
+ $messages as xs:long+,
+ $uid as xs:boolean?)
+ as empty-sequence()
+{
+ imap:copy-impl(validate {$host-info}, $mailbox-from, $mailbox-to, $messages, $uid, true());
+};
+
+declare %private %an:sequential function imap:copy-impl($host-info as element(email:hostInfo), $mailbox-from as xs:string, $mailbox-to as xs:string, $messages as xs:long+, $uid as xs:boolean?, $copy as xs:boolean) as empty-sequence() external;
+
+(:~
+ : Moves messages between mailboxes.
+ :
+ : Depending on the value of <code>$uid</code>, the messages are either specified through
+ : their sequence number or through their unique id. Both mailboxes must exist.
+ :
+ : @param $host-info The IMAP host, user name, and password.
+ : @param $mailbox-from The mailbox in which the messages reside.
+ : @param $mailbox-to The mailbox in to which the messages should be moved.
+ : @param $messages The messages to be copied, specified either by their sequence number or their unique id.
+ : @param $uid If true, <code>$messages</code> are treated as sequence numbers. Else as unique identifiers.
+ : @return The function is declared as sequential and has side-effects. It returns the empty sequence.
+ : @error imap:IMAP0001 If the IMAP operation failed.
+ : @error imap:IMAP0002 If the connection to the IMAP server is refused.
+ : @error imap:IMAP0003 If no message is found with the provided sequence number/unique identifier.
+ : @error err:XQDY0027 If the value of <code>$host-info</code> is not valid
+ : according to the email schema:
+ : <code>http://www.zorba-xquery.com/modules/email</code>
+ : @example examples/Queries/imap/move_example.xq
+ :)
+declare %an:sequential function imap:move(
+ $host-info as element(email:hostInfo),
+ $mailbox-from as xs:string,
+ $mailbox-to as xs:string,
+ $messages as xs:long+,
+ $uid as xs:boolean?)
+ as empty-sequence()
+{
+ imap:copy-impl(validate {$host-info}, $mailbox-from, $mailbox-to, $messages, $uid, false());
+};
+
+(:~
+ : Fetches the envelope of a message.
+ :
+ : @param $host-info The IMAP host, user name, and password.
+ : @param $mailbox The mailbox in which to search for the message.
+ : @param $message-number The message for which to fetch the envelope (depending on
+ : <code>$uid</code> either as message sequence number or unique identifier).
+ : @param $uid If true, <code>$message-number</code> is treated as sequence number. Else as unique identifier.
+ : @return The <code>envelope</code> of the requested message.
+ : The result is validated against the schema:
+ : <code>http://www.zorba-xquery.com/modules/email</code>.
+ : @error imap:IMAP0001 If the IMAP operation failed.
+ : @error imap:IMAP0002 If the connection to the IMAP server is refused.
+ : @error imap:IMAP0003 If no message is found with the provided sequence number/unique identifier.
+ : @error err:XQDY0027 If the value of <code>$host-info</code> is not valid
+ : according to the email schema:
+ : <code>http://www.zorba-xquery.com/modules/email</code>
+ : @example examples/Queries/imap/fetch_envelope_example.xq
+ :)
+declare %an:nondeterministic function imap:fetch-envelope(
+ $host-info as element(email:hostInfo),
+ $mailbox as xs:string,
+ $message-number as xs:long,
+ $uid as xs:boolean?)
+ as element(email:envelope)
+{
+ validate {imap:fetch-envelope-impl( validate { $host-info }, $mailbox , $message-number, $uid )}
+};
+
+declare %private %an:nondeterministic function imap:fetch-envelope-impl($host-info as element(email:hostInfo), $mailbox as xs:string, $message-number as xs:long, $uid as xs:boolean?) as element(email:envelope) external;
+
+(:~
+ : Fetches a whole message.
+ :
+ : @param $host-info The IMAP host, user name, and password.
+ : @param $mailbox The mailbox in which to search for the message.
+ : @param $message-number The message to fetch, denoted either by its sequence number or unique identifier.
+ : @param $uid If true, <code>$message-number</code> is treated as sequence number. Else as unique identifier.
+ : @return the <code>message</code> with the given <code>$message-number</code>.
+ : The result is validated against the schema:
+ : <code>http://www.zorba-xquery.com/modules/email</code>.
+ : @error imap:IMAP0001 If the IMAP operation failed.
+ : @error imap:IMAP0002 If the connection to the IMAP server is refused.
+ : @error imap:IMAP0003 If no message is found with the provided sequence number/unique identifier.
+ : @error err:XQDY0027 If the value of <code>$host-info</code> is not valid
+ : according to the email schema:
+ : <code>http://www.zorba-xquery.com/modules/email</code>
+ : @example examples/Queries/imap/fetch_message_example.xq
+ :)
+declare %an:nondeterministic function imap:fetch-message(
+ $host-info as element(email:hostInfo),
+ $mailbox as xs:string,
+ $message-number as xs:long,
+ $uid as xs:boolean)
+ as element(email:message)
+{
+ validate {imap:fetch-message-impl(validate {$host-info}, $mailbox, $message-number, $uid)}
+};
+
+declare %private %an:nondeterministic function imap:fetch-message-impl($host-info as element(email:hostInfo), $mailbox as xs:string, $message-number as xs:long, $uid as xs:boolean) as element() external;
+
+(:~
+ : Fetches the subject for a message.
+ :
+ : Please note that this function only works with message sequence numbers,
+ : not with unique identifiers. Only the first 255 characters of a subject
+ : are fetched.
+ :
+ : @param $host-info The IMAP host, user name, and password.
+ : @param $mailbox The mailbox for which we want to get the subject of a message.
+ : @param $message-number Denotes the message for which we want the subject.
+ : @return The subject of the specified message.
+ : @error imap:IMAP0001 If the IMAP operation failed.
+ : @error imap:IMAP0002 If the connection to the IMAP server is refused.
+ : @error imap:IMAP0003 If no message is found with the provided sequence number/unique identifier.
+ : @error err:XQDY0027 If the value of <code>$host-info</code> is not valid
+ : according to the email schema:
+ : <code>http://www.zorba-xquery.com/modules/email</code>
+ : @example examples/Queries/imap/fetch_subject_example.xq
+ :)
+declare %an:nondeterministic function imap:fetch-subject(
+ $host-info as element(email:hostInfo),
+ $mailbox as xs:string,
+ $message-number as xs:long)
+ as xs:string
+{
+ imap:fetch-subject-impl(validate {$host-info}, $mailbox, $message-number)
+};
+
+declare %private %an:nondeterministic function imap:fetch-subject-impl($host-info as element(email:hostInfo), $mailbox as xs:string, $message-number as xs:long) as xs:string external;
+
+(:~
+ : Fetches the 'from' string of a message.
+ :
+ : Please note that this function only words with message sequence numbers,
+ : not with unique identifiers. Only the first 255 characters of a 'from'
+ : string are fetched.
+ :
+ : @param $host-info The IMAP host, user name, and password.
+ : @param $mailbox The mailbox for which we want to get the 'from' string of a message.
+ : @param $message-number Denotes the message for which we want the 'from' string.
+ : @return The 'from' string of the specified message.
+ : @error imap:IMAP0001 If the IMAP operation failed.
+ : @error imap:IMAP0002 If the connection to the IMAP server is refused.
+ : @error imap:IMAP0003 If no message is found with the provided sequence number/unique identifier.
+ : @error err:XQDY0027 If the value of <code>$host-info</code> is not valid
+ : according to the email schema:
+ : <code>http://www.zorba-xquery.com/modules/email</code>
+ : @example examples/Queries/imap/fetch_from_example.xq
+ :)
+declare %an:nondeterministic function imap:fetch-from(
+ $host-info as element(email:hostInfo),
+ $mailbox as xs:string,
+ $message-number as xs:long)
+ as xs:string
+{
+ imap:fetch-from-impl(validate {$host-info}, $mailbox, $message-number)
+};
+
+declare %private %an:nondeterministic function imap:fetch-from-impl($host-info as element(email:hostInfo), $mailbox as xs:string, $message-number as xs:long) as xs:string external;
+
+(:~
+ : Fetches the unique identifier for a given message sequence number.
+ :
+ : @param $host-info The IMAP host, user name, and password.
+ : @param $mailbox The mailbox for which we want to get the unique identifier of a message sequence number.
+ : @param $message-number The message sequence number for which we want the unique identifier.
+ : @return The unique identifier of the given message sequence number.
+ : @error imap:IMAP0001 If the IMAP operation failed.
+ : @error imap:IMAP0002 If the connection to the IMAP server is refused.
+ : @error imap:IMAP0003 If no message is found with the provided sequence number/unique identifier.
+ : @error err:XQDY0027 If the value of <code>$host-info</code> is not valid
+ : according to the email schema:
+ : <code>http://www.zorba-xquery.com/modules/email</code>
+ : @example examples/Queries/imap/fetch_uid_example.xq
+ :)
+declare %an:nondeterministic function imap:fetch-uid(
+ $host-info as element(email:hostInfo),
+ $mailbox as xs:string,
+ $message-number as xs:long)
+ as xs:long
+{
+ imap:fetch-uid-impl(validate {$host-info}, $mailbox, $message-number)
+};
+
+declare %private %an:nondeterministic function imap:fetch-uid-impl($host-info as element(email:hostInfo), $mailbox as xs:string, $message-number as xs:long) as xs:long external;
+
+(:~
+ : Fetches the message sequence number for a given unique identifier.
+ :
+ : @param $host-info The IMAP host, user name, and password.
+ : @param $mailbox The mailbox for which we want to get the message sequence number of an unique identifier.
+ : @param $message-number The unique identifier for which we want the message sequence number.
+ : @return The message sequence number of the of the given unique identifier.
+ : @error imap:IMAP0001 If the IMAP operation failed.
+ : @error imap:IMAP0002 If the connection to the IMAP server is refused.
+ : @error imap:IMAP0003 If no message is found with the provided sequence number/unique identifier.
+ : @error err:XQDY0027 If the value of <code>$host-info</code> is not valid
+ : according to the email schema:
+ : <code>http://www.zorba-xquery.com/modules/email</code>
+ : @example examples/Queries/imap/fetch_message_sequence_number_example.xq
+ :)
+declare %an:nondeterministic function imap:fetch-message-sequence-number(
+ $host-info as element(email:hostInfo),
+ $mailbox as xs:string,
+ $message-number as xs:long)
+ as xs:long
+{
+ imap:fetch-message-sequence-number-impl(validate {$host-info}, $mailbox, $message-number)
+};
+
+declare %private %an:nondeterministic function imap:fetch-message-sequence-number-impl($host-info as element(email:hostInfo), $mailbox as xs:string, $message-number as xs:long) as xs:long external;
+
+(:~
+ : Fetches the flags of a message.
+ :
+ : @param $host-info The IMAP host, user name, and password.
+ : @param $mailbox The mailbox containing the specified message.
+ : @param $message-number Either the message sequence number or the unique identifier of the message.
+ : @param $uid If true, <code>$message-number</code> is treated as sequence number. Else as unique identifier.
+ : @return The <code>flags</code> of the specified message.
+ : The result is validated against the schema:
+ : <code>http://www.zorba-xquery.com/modules/email</code>.
+ : @error imap:IMAP0001 If the IMAP operation failed.
+ : @error imap:IMAP0002 If the connection to the IMAP server is refused.
+ : @error imap:IMAP0003 If no message is found with the provided sequence number/unique identifier.
+ : @error err:XQDY0027 If the value of <code>$host-info</code> is not valid
+ : according to the email schema:
+ : <code>http://www.zorba-xquery.com/modules/email</code>
+ : @example examples/Queries/imap/fetch_flags_example.xq
+ :)
+declare %an:nondeterministic function imap:fetch-flags(
+ $host-info as element(email:hostInfo),
+ $mailbox as xs:string,
+ $message-number as xs:long,
+ $uid as xs:boolean?)
+ as element(email:flags)
+{
+ validate {imap:fetch-flags-impl(validate{$host-info}, $mailbox, $message-number, $uid)}
+};
+
+declare %private %an:nondeterministic function imap:fetch-flags-impl($host-info as element(email:hostInfo), $mailbox as xs:string, $message-number as xs:long, $uid as xs:boolean?) as element(email:flags) external;
+
+(:~
+ : Sets the flags for a given message.
+ :
+ : The flags are set and unset according to the passed <code>$flags</code>.
+ :
+ : @param $host-info The IMAP host, user name, and password.
+ : @param $mailbox The mailbox containing the specified message.
+ : @param $message-number Either the message sequence number or the unique
+ : identifier of the message (depending on the value of <code>$uid</code>).
+ : @param $flags Defines which flags should be set for this message.
+ : The possibilities are "seen", "deleted", "flagged", "answered", and "draft".
+ : Setting all flags at once is done by passing the element:
+ : <code>
+ : <email:flags>
+ : <email:seen/>
+ : <email:deleted/>
+ : <email:flagged/>
+ : <email:answered/>
+ : <email:draft/>
+ : </email:flags>
+ : </code>.
+ :
+ : Setting "flagged" only and unsetting all other at once can be done by passing:
+ : <code>
+ : <email:flags>
+ : <email:flagged/>
+ : </email:flags>
+ : </code>.
+ : @param $uid If true, <code>$message-number</code> is treated as sequence number. Else as unique identifier.
+ : @return The function is declared as sequential and has side-effects. It returns the empty sequence.
+ : @error imap:IMAP0001 If the IMAP operation failed.
+ : @error imap:IMAP0002 If the connection to the IMAP server is refused.
+ : @error imap:IMAP0003 If no message is found with the provided sequence number/unique identifier.
+ : @error err:XQDY0027 If the value of <code>$host-info</code> is not valid
+ : according to the email schema:
+ : <code>http://www.zorba-xquery.com/modules/email</code>
+ : @example examples/Queries/imap/set_flags_example.xq
+ :)
+declare %an:sequential function imap:set-flags(
+ $host-info as element(email:hostInfo),
+ $mailbox as xs:string,
+ $message-number as xs:long,
+ $flags as element(email:flags),
+ $uid as xs:boolean?)
+ as empty-sequence()
+{
+ imap:set-flags-impl(validate{$host-info}, $mailbox, $message-number, validate{$flags}, $uid)
+};
+
+declare %private %an:sequential function imap:set-flags-impl($host-info as element(email:hostInfo), $mailbox as xs:string, $message-number as xs:long, $flags as element(email:flags), $uid as xs:boolean?) as empty-sequence() external;
=== added directory 'src/com/zorba-xquery/www/modules/email/imap.xq.src'
=== added file 'src/com/zorba-xquery/www/modules/email/imap.xq.src/imap.cpp'
--- src/com/zorba-xquery/www/modules/email/imap.xq.src/imap.cpp 1970-01-01 00:00:00 +0000
+++ src/com/zorba-xquery/www/modules/email/imap.xq.src/imap.cpp 2014-04-30 23:07:12 +0000
@@ -0,0 +1,866 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "imap.h"
+
+#include <iostream>
+#include <sstream>
+#include <algorithm>
+#include <string>
+
+#include <zorba/singleton_item_sequence.h>
+#include <zorba/vector_item_sequence.h>
+#include <zorba/empty_sequence.h>
+#include <zorba/user_exception.h>
+#include <zorba/xquery_functions.h>
+
+#include "imap_module.h"
+#include "imap_client.h"
+#include "email_exception.h"
+
+
+namespace zorba { namespace emailmodule {
+
+
+//*****************************************************************************
+
+StatusFunction::StatusFunction(const ImapModule* aModule)
+ : ImapFunction(aModule)
+{
+}
+
+ItemSequence_t
+StatusFunction::evaluate(
+ const ExternalFunction::Arguments_t& aArgs,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const
+{
+ try {
+ std::string lHostName;
+ std::string lUserName;
+ std::string lPassword;
+ getHostUserPassword(aArgs, 0, lHostName, lUserName, lPassword);
+ String lMailbox = getOneStringArg(aArgs, 1);
+ ImapClient::Instance().status(lHostName, lUserName, lPassword, lMailbox.c_str());
+ std::string lErrorMessage = ImapClient::Instance().getError();
+ if (lErrorMessage.size() != 0) {
+ raiseImapError("IMAP0001", lErrorMessage);
+ }
+
+ unsigned long lMessages;
+ unsigned long lRecent;
+ unsigned long lUnseen;
+ unsigned long lUIDNext;
+ unsigned long lUIDValidity;
+
+ ImapClient::Instance().getStatus(&lMessages, &lRecent, &lUnseen, &lUIDNext, &lUIDValidity);
+
+ std::stringstream lResult;
+ lResult << lMessages << "," << lRecent << "," << lUnseen << "," << lUIDNext << "," << lUIDValidity;
+
+ std::string lResultString = lResult.str();
+ return ItemSequence_t(new SingletonItemSequence(
+ theModule->getItemFactory()->createString(lResultString.c_str())));
+ } catch (EmailException& e) {
+ raiseImapError(e);
+ }
+ return ItemSequence_t(NULL);
+}
+
+//*****************************************************************************
+
+CreateFunction::CreateFunction(const ImapModule* aModule)
+ : ImapFunction(aModule)
+{
+}
+
+ItemSequence_t
+CreateFunction::evaluate(
+ const ExternalFunction::Arguments_t& aArgs,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const
+{
+ try {
+ std::string lHostName;
+ std::string lUserName;
+ std::string lPassword;
+ getHostUserPassword(aArgs, 0, lHostName, lUserName, lPassword);
+ String lMailboxName = getOneStringArg(aArgs, 1);
+ bool lSuccess = ImapClient::Instance().create(lHostName, lUserName, lPassword, lMailboxName.c_str());
+ if (!lSuccess) {
+ std::string lErrorMessage = ImapClient::Instance().getError();
+ raiseImapError("IMAP0001", lErrorMessage);
+ }
+
+ } catch (EmailException& e) {
+ raiseImapError(e);
+ }
+ return ItemSequence_t(NULL);
+}
+
+//*****************************************************************************
+
+DeleteFunction::DeleteFunction(const ImapModule* aModule)
+ : ImapFunction(aModule)
+{
+}
+
+ItemSequence_t
+DeleteFunction::evaluate(
+ const ExternalFunction::Arguments_t& aArgs,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const
+{
+ try {
+ std::string lHostName;
+ std::string lUserName;
+ std::string lPassword;
+ getHostUserPassword(aArgs, 0, lHostName, lUserName, lPassword);
+ String lMailboxName = getOneStringArg(aArgs, 1);
+ bool lSuccess = ImapClient::Instance().delete_mailbox(lHostName, lUserName, lPassword, lMailboxName.c_str());
+
+ if (!lSuccess) {
+ std::string lErrorMessage = ImapClient::Instance().getError();
+ raiseImapError("IMAP0001", lErrorMessage);
+ }
+
+ } catch (EmailException& e) {
+ raiseImapError(e);
+ }
+ return ItemSequence_t(NULL);
+}
+
+//*****************************************************************************
+
+RenameFunction::RenameFunction(const ImapModule* aModule)
+ : ImapFunction(aModule)
+{
+}
+
+ItemSequence_t
+RenameFunction::evaluate(
+ const ExternalFunction::Arguments_t& aArgs,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const
+{
+ try {
+ std::string lHostName;
+ std::string lUserName;
+ std::string lPassword;
+ getHostUserPassword(aArgs, 0, lHostName, lUserName, lPassword);
+ String lMailboxFromName = getOneStringArg(aArgs, 1);
+ String lMailboxToName = getOneStringArg(aArgs, 2);
+ bool lSuccess = ImapClient::Instance().rename(lHostName, lUserName, lPassword, lMailboxFromName.c_str(), lMailboxToName.c_str());
+ if (!lSuccess) {
+ std::string lErrorMessage = ImapClient::Instance().getError();
+ raiseImapError("IMAP0001", lErrorMessage);
+ }
+
+ } catch (EmailException& e) {
+ raiseImapError(e);
+ }
+ return ItemSequence_t(NULL);
+}
+
+//*****************************************************************************
+
+ListFunction::ListFunction(const ImapModule* aModule)
+ : ImapFunction(aModule)
+{
+}
+
+ItemSequence_t
+ListFunction::evaluate(
+ const ExternalFunction::Arguments_t& aArgs,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const
+{
+ try {
+ std::string lHostName;
+ std::string lUserName;
+ std::string lPassword;
+ getHostUserPassword(aArgs, 0, lHostName, lUserName, lPassword);
+ String lReferencePath = getOneStringArg(aArgs, 1);
+ String lPattern = getOneStringArg(aArgs, 2);
+ bool lOnlySuscribed = getOneBoolArg(aArgs, 3);
+
+ std::vector<std::string> lListedMailboxes = ImapClient::Instance().list(lHostName, lUserName, lPassword, lReferencePath.c_str(), lPattern.c_str(), lOnlySuscribed);
+ std::string lErrorMessage = ImapClient::Instance().getError();
+ if (lErrorMessage.size() != 0) {
+ raiseImapError("IMAP0001", lErrorMessage);
+ }
+ // explicitly return an empty sequence if there are no elements to return
+ if (lListedMailboxes.size() == 0) {
+ return ItemSequence_t(new EmptySequence());
+ }
+
+ int lVectorSize = (int)lListedMailboxes.size();
+ std::vector<Item> lItemVector;
+ for (int i = 0; i < lVectorSize; i++) {
+ lItemVector.push_back(theModule->getItemFactory()->createString(lListedMailboxes[i]));
+ }
+
+ return ItemSequence_t(new VectorItemSequence(lItemVector));
+ } catch (EmailException& e) {
+ raiseImapError(e);
+ }
+ return ItemSequence_t(NULL);
+}
+
+//*****************************************************************************
+
+SubscribeFunction::SubscribeFunction(const ImapModule* aModule)
+ : ImapFunction(aModule)
+{
+}
+
+ItemSequence_t
+SubscribeFunction::evaluate(
+ const ExternalFunction::Arguments_t& aArgs,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const
+{
+ try {
+ std::string lHostName;
+ std::string lUserName;
+ std::string lPassword;
+ getHostUserPassword(aArgs, 0, lHostName, lUserName, lPassword);
+ String lMailbox = getOneStringArg(aArgs, 1);
+
+ bool lSuccess = ImapClient::Instance().subscription(lHostName, lUserName, lPassword, lMailbox.c_str(), true);
+ if (!lSuccess) {
+ std::string lErrorMessage = ImapClient::Instance().getError();
+ raiseImapError("IMAP0001", lErrorMessage);
+ }
+
+ } catch (EmailException& e) {
+ raiseImapError(e);
+ }
+ return ItemSequence_t(NULL);
+}
+
+//*****************************************************************************
+
+UnsubscribeFunction::UnsubscribeFunction(const ImapModule* aModule)
+ : ImapFunction(aModule)
+{
+}
+
+ItemSequence_t
+UnsubscribeFunction::evaluate(
+ const ExternalFunction::Arguments_t& aArgs,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const
+{
+ try {
+ std::string lHostName;
+ std::string lUserName;
+ std::string lPassword;
+ getHostUserPassword(aArgs, 0, lHostName, lUserName, lPassword);
+ String lMailbox = getOneStringArg(aArgs, 1);
+
+ bool lSuccess = ImapClient::Instance().subscription(lHostName, lUserName, lPassword, lMailbox.c_str(), false);
+ if (!lSuccess) {
+ std::string lErrorMessage = ImapClient::Instance().getError();
+ raiseImapError("IMAP0001", lErrorMessage);
+ }
+
+ } catch (EmailException& e) {
+ raiseImapError(e);
+ }
+ return ItemSequence_t(NULL);
+}
+
+//*****************************************************************************
+
+ExpungeFunction::ExpungeFunction(const ImapModule* aModule)
+ : ImapFunction(aModule)
+{
+}
+
+ItemSequence_t
+ExpungeFunction::evaluate(
+ const ExternalFunction::Arguments_t& aArgs,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const
+{
+ try {
+ std::string lHostName;
+ std::string lUserName;
+ std::string lPassword;
+ getHostUserPassword(aArgs, 0, lHostName, lUserName, lPassword);
+ String lMailbox = getOneStringArg(aArgs, 1);
+
+ bool lSuccess = ImapClient::Instance().expunge(lHostName, lUserName, lPassword, lMailbox.c_str());
+ if (!lSuccess) {
+ std::string lErrorMessage = ImapClient::Instance().getError();
+ raiseImapError("IMAP0001", lErrorMessage);
+ }
+
+ } catch (EmailException& e) {
+ raiseImapError(e);
+ }
+ return ItemSequence_t(NULL);
+}
+
+//*****************************************************************************
+
+SearchFunction::SearchFunction(const ImapModule* aModule)
+ : ImapFunction(aModule)
+{
+}
+
+ItemSequence_t
+SearchFunction::evaluate(
+ const ExternalFunction::Arguments_t& aArgs,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const
+{
+ try {
+ std::string lHostName;
+ std::string lUserName;
+ std::string lPassword;
+ getHostUserPassword(aArgs, 0, lHostName, lUserName, lPassword);
+ String lMailbox = getOneStringArg(aArgs, 1);
+ String lCriteria = getOneStringArg(aArgs, 2);
+ // get none or one boolean arg
+ bool lUid = false;
+ Item lItem;
+ Iterator_t arg3_iter = aArgs[3]->getIterator();
+ arg3_iter->open();
+ if (arg3_iter->next(lItem)) {
+ lUid = lItem.getBooleanValue();
+ }
+ arg3_iter->close();
+ std::vector<long> lFoundSequenceNumbers = ImapClient::Instance().search(lHostName, lUserName, lPassword, lMailbox.c_str(), lCriteria.c_str(), lUid);
+
+ // throw zorba exception if we have an error log
+ std::string lErrorMessage = ImapClient::Instance().getError();
+ if (lErrorMessage.size() != 0) {
+ raiseImapError("IMAP0001", lErrorMessage);
+ }
+
+ int lVectorSize =(int)lFoundSequenceNumbers.size();
+ std::vector<Item> lItemVector;
+ for (int i = 0; i < lVectorSize; i++) {
+ lItemVector.push_back(theModule->getItemFactory()->createLong(lFoundSequenceNumbers[i]));
+ }
+
+ return ItemSequence_t(new VectorItemSequence(lItemVector));
+ } catch (EmailException& e) {
+ raiseImapError(e);
+ }
+ return ItemSequence_t(NULL);
+}
+
+//*****************************************************************************
+
+CopyFunction::CopyFunction(const ImapModule* aModule)
+ : ImapFunction(aModule)
+{
+}
+
+ItemSequence_t
+CopyFunction::evaluate(
+ const ExternalFunction::Arguments_t& aArgs,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const
+{
+ try {
+ std::string lHostName;
+ std::string lUserName;
+ std::string lPassword;
+ getHostUserPassword(aArgs, 0, lHostName, lUserName, lPassword);
+ String lMailboxFrom = getOneStringArg(aArgs, 1);
+ String lMailboxTo = getOneStringArg(aArgs, 2);
+ // find out if we are working with uid's instead of sequence numbers.
+ bool lUid = false;
+ Item lItem;
+
+ Iterator_t arg4_iter = aArgs[4]->getIterator();
+ arg4_iter->open();
+ if (arg4_iter->next(lItem)) {
+ lUid = lItem.getBooleanValue();
+ }
+ arg4_iter->close();
+ Iterator_t arg5_iter = aArgs[5]->getIterator();
+ arg5_iter->open();
+ bool lCopy = false;
+ if (arg5_iter->next(lItem)) {
+ lCopy = lItem.getBooleanValue();
+ }
+ arg5_iter->close();
+
+ std::string lMessageNumbers = getMessageNumbers(aArgs, 3);
+
+ bool lSuccess = ImapClient::Instance().copy(lHostName, lUserName, lPassword, lMailboxFrom.c_str(), lMailboxTo.c_str(), lMessageNumbers, lUid, lCopy);
+ if (!lSuccess) {
+ std::string lErrorMessage = ImapClient::Instance().getError();
+ raiseImapError("IMAP0001", lErrorMessage);
+ }
+
+ } catch (EmailException& e) {
+ raiseImapError(e);
+ }
+ return ItemSequence_t(NULL);
+}
+
+//*****************************************************************************
+
+FetchEnvelopeFunction::FetchEnvelopeFunction(const ImapModule* aModule)
+ : ImapFunction(aModule)
+{
+}
+
+ItemSequence_t
+FetchEnvelopeFunction::evaluate(
+ const ExternalFunction::Arguments_t& aArgs,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const
+{
+ try {
+ std::string lHostName;
+ std::string lUserName;
+ std::string lPassword;
+ getHostUserPassword(aArgs, 0, lHostName, lUserName, lPassword);
+ String lMailbox = getOneStringArg(aArgs, 1);
+
+ unsigned long lMessageNumber = getOneMessageNumber(aArgs, 2);
+
+ bool lUid = false;
+ Item lItem;
+ Iterator_t arg3_iter = aArgs[3]->getIterator();
+ arg3_iter->open();
+ if (arg3_iter->next(lItem)) {
+ lUid = lItem.getBooleanValue();
+ }
+ arg3_iter->close();
+
+ Item lParent;
+ getMessage(lParent,
+ lHostName.c_str(), lUserName.c_str(), lPassword.c_str(),
+ lMailbox.c_str(), lMessageNumber,
+ lUid, true);
+
+ std::string lErrorMessage = ImapClient::Instance().getError();
+ if (lErrorMessage.size() != 0) {
+ raiseImapError("IMAP0001", lErrorMessage);
+ }
+
+ return ItemSequence_t(new SingletonItemSequence(lParent));
+
+ } catch (EmailException& e) {
+ raiseImapError(e);
+ }
+ return ItemSequence_t(NULL);
+}
+
+//*****************************************************************************
+
+FetchSubjectFunction::FetchSubjectFunction(const ImapModule* aModule)
+ : ImapFunction(aModule)
+{
+}
+
+ItemSequence_t
+FetchSubjectFunction::evaluate(
+ const ExternalFunction::Arguments_t& aArgs,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const
+{
+ try {
+ std::string lHostName;
+ std::string lUserName;
+ std::string lPassword;
+ getHostUserPassword(aArgs, 0, lHostName, lUserName, lPassword);
+ String lMailbox = getOneStringArg(aArgs, 1);
+ unsigned long lMessageNumber = getOneMessageNumber(aArgs, 2);
+ std::string lRawSubject =
+ ImapClient::Instance().fetchSubject(
+ lHostName,
+ lUserName,
+ lPassword,
+ lMailbox.c_str(),
+ lMessageNumber);
+
+ // decode the subject header because it can contain encoded words
+ std::string lDecodedSubject;
+ decodeHeader(lRawSubject, lDecodedSubject);
+
+ std::string lErrorMessage = ImapClient::Instance().getError();
+ if (lErrorMessage.size() != 0) {
+ raiseImapError("IMAP0001", lErrorMessage);
+ }
+
+ return ItemSequence_t(new SingletonItemSequence(theModule->getItemFactory()->createString(lDecodedSubject)));
+
+ } catch (EmailException& e) {
+ raiseImapError(e);
+ }
+ return ItemSequence_t(NULL);
+}
+
+//*****************************************************************************
+
+FetchFromFunction::FetchFromFunction(const ImapModule* aModule)
+ : ImapFunction(aModule)
+{
+}
+
+ItemSequence_t
+FetchFromFunction::evaluate(
+ const ExternalFunction::Arguments_t& aArgs,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const
+{
+ try {
+ std::string lHostName;
+ std::string lUserName;
+ std::string lPassword;
+ getHostUserPassword(aArgs, 0, lHostName, lUserName, lPassword);
+ String lMailbox = getOneStringArg(aArgs, 1);
+ unsigned long lMessageNumber = getOneMessageNumber(aArgs, 2);
+ String lResult = ImapClient::Instance().fetchFrom(lHostName, lUserName, lPassword, lMailbox.c_str(), lMessageNumber);
+
+ std::string lErrorMessage = ImapClient::Instance().getError();
+ if (lErrorMessage.size() != 0) {
+ raiseImapError("IMAP0001", lErrorMessage);
+ }
+
+
+ return ItemSequence_t(new SingletonItemSequence(
+ theModule->getItemFactory()->createString(lResult)));
+ } catch (EmailException& e) {
+ raiseImapError(e);
+ }
+ return ItemSequence_t(NULL);
+}
+
+//*****************************************************************************
+
+FetchFlagsFunction::FetchFlagsFunction(const ImapModule* aModule)
+ : ImapFunction(aModule)
+{
+}
+
+ItemSequence_t
+FetchFlagsFunction::evaluate(
+ const ExternalFunction::Arguments_t& aArgs,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const
+{
+ try {
+ std::string lHostName;
+ std::string lUserName;
+ std::string lPassword;
+ getHostUserPassword(aArgs, 0, lHostName, lUserName, lPassword);
+ String lMailbox = getOneStringArg(aArgs, 1);
+ unsigned long lMessageNumber = getOneMessageNumber(aArgs, 2);
+ bool lUid = false;
+ Item lItem;
+ Iterator_t arg3_iter = aArgs[3]->getIterator();
+ arg3_iter->open();
+ if (arg3_iter->next(lItem)) {
+ lUid = lItem.getBooleanValue();
+ }
+ arg3_iter->close();
+
+ // null parent
+ Item lParent;
+ std::vector<int> lFlags(6, 0);
+
+ ImapClient::Instance().fetchFlags(lHostName, lUserName, lPassword, lMailbox.c_str(), lMessageNumber,lFlags, lUid);
+
+ std::string lErrorMessage = ImapClient::Instance().getError();
+ if (lErrorMessage.size() != 0) {
+ raiseImapError("IMAP0001", lErrorMessage);
+ }
+
+
+ Item lFlagsItem;
+ createFlagsNode(lParent, lFlagsItem, lFlags, true);
+
+ return ItemSequence_t(new SingletonItemSequence(lFlagsItem));
+ } catch (EmailException& e) {
+ raiseImapError(e);
+ }
+ return ItemSequence_t(NULL);
+}
+
+//*****************************************************************************
+
+SetFlagsFunction::SetFlagsFunction(const ImapModule* aModule)
+ : ImapFunction(aModule)
+{
+}
+
+ItemSequence_t
+SetFlagsFunction::evaluate(
+ const ExternalFunction::Arguments_t& aArgs,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const
+{
+ try {
+ std::string lHostName;
+ std::string lUserName;
+ std::string lPassword;
+ getHostUserPassword(aArgs, 0, lHostName, lUserName, lPassword);
+ String lMailbox = getOneStringArg(aArgs, 1);
+ unsigned long lMessageNumber = getOneMessageNumber(aArgs, 2);
+
+ std::vector<int> lFlags(6, 0);
+ SetFlagsFunction::getFlagsVector(aArgs, lFlags);
+
+ bool lUid = false;
+ Item lItem;
+ Iterator_t arg4_iter = aArgs[4]->getIterator();
+ arg4_iter->open();
+ if (arg4_iter->next(lItem)) {
+ lUid = lItem.getBooleanValue();
+ }
+ arg4_iter->close();
+
+ ImapClient::Instance().setFlags(lHostName, lUserName, lPassword, lMailbox.c_str(), lMessageNumber, lFlags, lUid);
+
+ std::string lErrorMessage = ImapClient::Instance().getError();
+ if (lErrorMessage.size() != 0) {
+ raiseImapError("IMAP0001", lErrorMessage);
+ }
+
+ } catch (EmailException& e) {
+ raiseImapError(e);
+ }
+ return ItemSequence_t(NULL);
+}
+
+void
+SetFlagsFunction::getFlagsVector(
+ const ExternalFunction::Arguments_t& aArgs,
+ std::vector<int>& aFlags)
+{
+ Item lFlagsNode;
+ Iterator_t arg3_iter = aArgs[3]->getIterator();
+ arg3_iter->open();
+ arg3_iter->next(lFlagsNode);
+ arg3_iter->close();
+ Iterator_t lChildren = lFlagsNode.getChildren();
+ lChildren->open();
+ Item lChild;
+ while(lChildren->next(lChild)) {
+ Item lNameNode;
+ lChild.getNodeName(lNameNode);
+ String lName = lNameNode.getStringValue();
+ /* checking for ending of name as it is not sure how the prefix looks like */
+ if (fn::ends_with(lName,"n")) {
+ // seen
+ aFlags[0] = 1;
+ } else if (fn::ends_with(lName,"ted")) {
+ // deleted
+ aFlags[1] = 1;
+ } else if (fn::ends_with(lName,"ged")) {
+ // flagged
+ aFlags[2] = 1;
+ } else if (fn::ends_with(lName,"red")) {
+ // answered
+ aFlags[3] = 1;
+ } else if (fn::ends_with(lName,"ft")) {
+ // draft
+ aFlags[4] = 1;
+ }
+ }
+}
+
+//*****************************************************************************
+
+FetchUidFunction::FetchUidFunction(const ImapModule* aModule)
+ : ImapFunction(aModule)
+{
+}
+
+ItemSequence_t
+FetchUidFunction::evaluate(
+ const ExternalFunction::Arguments_t& aArgs,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const
+{
+ try {
+ std::string lHostName;
+ std::string lUserName;
+ std::string lPassword;
+ getHostUserPassword(aArgs, 0, lHostName, lUserName, lPassword);
+ String lMailbox = getOneStringArg(aArgs, 1);
+ unsigned long lMessageNumber = getOneMessageNumber(aArgs, 2);
+ unsigned long lResult = ImapClient::Instance().convertNumber(lHostName, lUserName, lPassword, lMailbox.c_str(), lMessageNumber, true);
+
+ return ItemSequence_t(new SingletonItemSequence(
+ theModule->getItemFactory()->createLong(lResult)));
+ } catch (EmailException& e) {
+ raiseImapError(e);
+ }
+ return ItemSequence_t(NULL);
+}
+
+//*****************************************************************************
+
+FetchMessageSequenceNumberFunction::FetchMessageSequenceNumberFunction(const ImapModule* aModule)
+ : ImapFunction(aModule)
+{
+}
+
+ItemSequence_t
+FetchMessageSequenceNumberFunction::evaluate(
+ const ExternalFunction::Arguments_t& aArgs,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const
+{
+ try {
+ std::string lHostName;
+ std::string lUserName;
+ std::string lPassword;
+ getHostUserPassword(aArgs, 0, lHostName, lUserName, lPassword);
+ String lMailbox = getOneStringArg(aArgs, 1);
+ unsigned long lMessageNumber = getOneMessageNumber(aArgs, 2);
+ unsigned long lResult = ImapClient::Instance().convertNumber(lHostName, lUserName, lPassword, lMailbox.c_str(), lMessageNumber, false);
+
+ return ItemSequence_t(new SingletonItemSequence(
+ theModule->getItemFactory()->createLong(lResult)));
+ } catch (EmailException& e) {
+ raiseImapError(e);
+ }
+ return ItemSequence_t(NULL);
+}
+
+//*****************************************************************************
+
+FetchMessageFunction::FetchMessageFunction(const ImapModule* aModule)
+ : ImapFunction(aModule)
+{
+}
+
+ItemSequence_t
+FetchMessageFunction::evaluate(
+ const ExternalFunction::Arguments_t& aArgs,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const
+{
+ try {
+ std::string lHostName; std::string lUserName; std::string lPassword;
+ getHostUserPassword(aArgs, 0, lHostName, lUserName, lPassword);
+ String lMailbox = getOneStringArg(aArgs, 1);
+
+ unsigned long lMessageNumber = getOneMessageNumber(aArgs, 2);
+
+ bool lUid = getOneBoolArg(aArgs, 3);
+
+ Item lParent;
+ getMessage(lParent,
+ lHostName.c_str(), lUserName.c_str(), lPassword.c_str(),
+ lMailbox.c_str(), lMessageNumber,
+ lUid, false);
+
+ return ItemSequence_t(new SingletonItemSequence(lParent));
+ } catch (EmailException& e) {
+ raiseImapError(e);
+ }
+ return ItemSequence_t(NULL);
+}
+
+
+// This function is defined here because if defined in imap_function.cpp
+// some header file conflict are raised and it does not compile
+void
+ImapFunction::decodeEncodedWords(
+ const std::string& aRawSubject,
+ std::string& aDecodedSubject) const
+{
+ std::size_t lLength = aRawSubject.length();
+ // if this is not a good format return the raw subject
+ if (lLength < 4 || (aRawSubject.find("=?") != 0 && aRawSubject.find("?=", lLength - 2) != lLength - 2)) {
+ aDecodedSubject = aRawSubject;
+ return;
+ }
+
+ // take out the part between the "=?" and "?="
+ std::string lToSplit = aRawSubject.substr(2, lLength - 4);
+
+ // get the charset
+ std::size_t lQPosTmp;
+ std::size_t lQPos = lToSplit.find("?");
+ if (lQPos == std::string::npos)
+ {
+ aDecodedSubject = aRawSubject;
+ return;
+ }
+ std::string lCharset = lToSplit.substr(0, lQPos);
+ lQPosTmp = lQPos + 1;
+
+ // get the encoding
+ lQPos = lToSplit.find("?", lQPosTmp);
+ if (lQPos == std::string::npos)
+ {
+ aDecodedSubject = aRawSubject;
+ return;
+ }
+ std::string lEncoding = lToSplit.substr(lQPosTmp, lQPos - lQPosTmp);
+ lQPosTmp = lQPos + 1;
+
+ // get the encoded data
+ lQPos = lToSplit.find("?", lQPos + 1);
+ if (lQPos != std::string::npos)
+ {
+ aDecodedSubject = aRawSubject;
+ return;
+ }
+ std::string lData = lToSplit.substr(lQPosTmp);
+
+ // binary
+ if (lEncoding == "B" || lEncoding == "b")
+ {
+ unsigned long lNewLength;
+ void* lNewData = rfc822_base64((unsigned char*)lData.c_str(), lData.length(), &lNewLength);
+ lData = std::string((char *)lNewData, lNewLength);
+ }
+ // quoted
+ else if (lEncoding == "Q" || lEncoding == "q")
+ {
+ unsigned long lNewLength;
+ void* lNewData = rfc822_qprint((unsigned char*)lData.c_str(), lData.length(), &lNewLength);
+ lData = std::string((char *)lNewData, lNewLength);
+ std::replace( lData.begin(), lData.end(), '_', ' ' );
+ }
+ // not a valid encoding?
+ else
+ {
+ aDecodedSubject = aRawSubject;
+ return;
+ }
+
+ // decode this fragment according to the charset
+ toUtf8(lData, lCharset.c_str(), aDecodedSubject);
+}
+
+} /* namespace emailmodule */
+} /* namespace zorba */
+
+#ifdef WIN32
+# define DLL_EXPORT __declspec(dllexport)
+#else
+# define DLL_EXPORT __attribute__ ((visibility("default")))
+#endif
+
+extern "C" DLL_EXPORT zorba::ExternalModule* createModule() {
+ return new zorba::emailmodule::ImapModule();
+}
=== added file 'src/com/zorba-xquery/www/modules/email/imap.xq.src/imap.h'
--- src/com/zorba-xquery/www/modules/email/imap.xq.src/imap.h 1970-01-01 00:00:00 +0000
+++ src/com/zorba-xquery/www/modules/email/imap.xq.src/imap.h 2014-04-30 23:07:12 +0000
@@ -0,0 +1,331 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ZORBA_EMAILMODULE_IMAP_H
+#define ZORBA_EMAILMODULE_IMAP_H
+
+#include <zorba/zorba_string.h>
+
+#include "imap_function.h"
+
+
+namespace zorba {
+
+ class ItemFactory;
+ class SerializationItemProvider;
+
+ namespace emailmodule {
+
+//*****************************************************************************
+
+ class StatusFunction : public ImapFunction
+ {
+ public:
+ StatusFunction(const ImapModule* aModule);
+
+ virtual String
+ getLocalName() const { return "status-impl"; }
+
+ virtual ItemSequence_t
+ evaluate(const ExternalFunction::Arguments_t& args,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const;
+ };
+
+//*****************************************************************************
+
+ class CreateFunction : public ImapFunction
+ {
+ public:
+ CreateFunction(const ImapModule* aModule);
+
+ virtual String
+ getLocalName() const { return "create-impl"; }
+
+ virtual ItemSequence_t
+ evaluate(const ExternalFunction::Arguments_t& args,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const;
+ };
+
+//*****************************************************************************
+
+ class DeleteFunction : public ImapFunction
+ {
+ public:
+ DeleteFunction(const ImapModule* aModule);
+
+ virtual String
+ getLocalName() const { return "delete-impl"; }
+
+ virtual ItemSequence_t
+ evaluate(const ExternalFunction::Arguments_t& args,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const;
+ };
+
+//*****************************************************************************
+
+ class RenameFunction : public ImapFunction
+ {
+ public:
+ RenameFunction(const ImapModule* aModule);
+
+ virtual String
+ getLocalName() const { return "rename-impl"; }
+
+ virtual ItemSequence_t
+ evaluate(const ExternalFunction::Arguments_t& args,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const;
+ };
+
+//*****************************************************************************
+
+ class ListFunction : public ImapFunction
+ {
+ public:
+ ListFunction(const ImapModule* aModule);
+
+ virtual String
+ getLocalName() const { return "list-impl"; }
+
+ virtual ItemSequence_t
+ evaluate(const ExternalFunction::Arguments_t& args,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const;
+ };
+
+//*****************************************************************************
+
+ class SubscribeFunction : public ImapFunction
+ {
+ public:
+ SubscribeFunction(const ImapModule* aModule);
+
+ virtual String
+ getLocalName() const { return "subscribe-impl"; }
+
+ virtual ItemSequence_t
+ evaluate(const ExternalFunction::Arguments_t& args,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const;
+ };
+
+//*****************************************************************************
+
+ class UnsubscribeFunction : public ImapFunction
+ {
+ public:
+ UnsubscribeFunction(const ImapModule* aModule);
+
+ virtual String
+ getLocalName() const { return "unsubscribe-impl"; }
+
+ virtual ItemSequence_t
+ evaluate(const ExternalFunction::Arguments_t& args,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const;
+ };
+
+//*****************************************************************************
+
+ class ExpungeFunction : public ImapFunction
+ {
+ public:
+ ExpungeFunction(const ImapModule* aModule);
+
+ virtual String
+ getLocalName() const { return "expunge-impl"; }
+
+ virtual ItemSequence_t
+ evaluate(const ExternalFunction::Arguments_t& args,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const;
+ };
+
+//*****************************************************************************
+
+ class SearchFunction : public ImapFunction
+ {
+ public:
+ SearchFunction(const ImapModule* aModule);
+
+ virtual String
+ getLocalName() const { return "search-impl"; }
+
+ virtual ItemSequence_t
+ evaluate(const ExternalFunction::Arguments_t& args,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const;
+ };
+
+//*****************************************************************************
+
+ class CopyFunction : public ImapFunction
+ {
+ public:
+ CopyFunction(const ImapModule* aModule);
+
+ virtual String
+ getLocalName() const { return "copy-impl"; }
+
+ virtual ItemSequence_t
+ evaluate(const ExternalFunction::Arguments_t& args,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const;
+ };
+
+//*****************************************************************************
+
+ class FetchEnvelopeFunction : public ImapFunction
+ {
+ public:
+ FetchEnvelopeFunction(const ImapModule* aModule);
+
+ virtual String
+ getLocalName() const { return "fetch-envelope-impl"; }
+
+ virtual ItemSequence_t
+ evaluate(const ExternalFunction::Arguments_t& args,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const;
+
+
+ };
+
+//*****************************************************************************
+
+ class FetchFlagsFunction : public ImapFunction
+ {
+ public:
+ FetchFlagsFunction(const ImapModule* aModule);
+
+ virtual String
+ getLocalName() const { return "fetch-flags-impl"; }
+
+ virtual ItemSequence_t
+ evaluate(const ExternalFunction::Arguments_t& args,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const;
+
+
+ };
+
+//*****************************************************************************
+
+ class SetFlagsFunction : public ImapFunction
+ {
+ public:
+ SetFlagsFunction(const ImapModule* aModule);
+
+ virtual String
+ getLocalName() const { return "set-flags-impl"; }
+
+ virtual ItemSequence_t
+ evaluate(const ExternalFunction::Arguments_t& args,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const;
+
+ static void
+ getFlagsVector(const ExternalFunction::Arguments_t& aArgs, std::vector<int>& aFlags);
+ };
+
+//*****************************************************************************
+
+ class FetchSubjectFunction : public ImapFunction
+ {
+ public:
+ FetchSubjectFunction(const ImapModule* aModule);
+
+ virtual String
+ getLocalName() const { return "fetch-subject-impl"; }
+
+ virtual ItemSequence_t
+ evaluate(const ExternalFunction::Arguments_t& args,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const;
+ };
+
+//*****************************************************************************
+
+ class FetchFromFunction: public ImapFunction
+ {
+ public:
+ FetchFromFunction(const ImapModule* aModule);
+
+ virtual String
+ getLocalName() const { return "fetch-from-impl"; }
+
+ virtual ItemSequence_t
+ evaluate(const ExternalFunction::Arguments_t& args,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const;
+ };
+
+//*****************************************************************************
+
+ class FetchUidFunction: public ImapFunction
+ {
+ public:
+ FetchUidFunction(const ImapModule* aModule);
+
+ virtual String
+ getLocalName() const { return "fetch-uid-impl"; }
+
+ virtual ItemSequence_t
+ evaluate(const ExternalFunction::Arguments_t& args,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const;
+ };
+
+//*****************************************************************************
+
+ class FetchMessageSequenceNumberFunction: public ImapFunction
+ {
+ public:
+ FetchMessageSequenceNumberFunction(const ImapModule* aModule);
+
+ virtual String
+ getLocalName() const { return "fetch-message-sequence-number-impl"; }
+
+ virtual ItemSequence_t
+ evaluate(const ExternalFunction::Arguments_t& args,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const;
+ };
+
+//*****************************************************************************
+
+ class FetchMessageFunction : public ImapFunction
+ {
+ public:
+ FetchMessageFunction(const ImapModule* aModule);
+
+ virtual String
+ getLocalName() const { return "fetch-message-impl"; }
+
+ virtual ItemSequence_t
+ evaluate(const ExternalFunction::Arguments_t& args,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const;
+ };
+
+
+} /* namespace emailmodule */
+} /* namespace zorba */
+
+#endif /* ZORBA_EMAILMODULE_FILE_H */
=== added file 'src/com/zorba-xquery/www/modules/email/imap.xq.src/imap_function.cpp'
--- src/com/zorba-xquery/www/modules/email/imap.xq.src/imap_function.cpp 1970-01-01 00:00:00 +0000
+++ src/com/zorba-xquery/www/modules/email/imap.xq.src/imap_function.cpp 2014-04-30 23:07:12 +0000
@@ -0,0 +1,957 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+#include <iostream>
+#include <map>
+#include <sstream>
+
+#include <unicode/ucnv.h>
+#include <unicode/ustring.h>
+
+#include <zorba/diagnostic_list.h>
+#include <zorba/iterator.h>
+#include <zorba/item_sequence.h>
+#include <zorba/user_exception.h>
+#include <zorba/util/base64_util.h>
+#include <zorba/zorba.h>
+
+#include "imap_function.h"
+#include "imap_module.h"
+#include "imap_client.h"
+#include "email_exception.h"
+
+namespace zorba { namespace emailmodule {
+
+const char* ImapFunction::SCHEMA_NAMESPACE = "http://www.zorba-xquery.com/modules/email";;
+const char* ImapFunction::SCHEMA_PREFIX = "email";
+
+ImapFunction::ImapFunction(const ImapModule* aModule)
+ : theModule(aModule)
+{
+}
+
+ImapFunction::~ImapFunction()
+{
+}
+
+void
+ImapFunction::raiseImapError(
+ EmailException& e) const
+{
+ std::string lCode;
+ if (e.get_localname() == "CONNECTION_ERROR") {
+ lCode = "IMAP0002";
+ }
+ else if (e.get_localname() == "WRONG_ID") {
+ lCode = "IMAP0003";
+ }
+ else {
+ lCode = "IMAP0001";
+ }
+ raiseImapError(lCode, e.get_message());
+}
+
+void
+ImapFunction::raiseImapError(
+ const std::string& qName,
+ const std::string& message) const
+{
+ Item lQName = theModule->getItemFactory()->createQName(getURI(), "imap", qName);
+ throw USER_EXCEPTION(lQName, message);
+}
+
+String
+ImapFunction::getURI() const
+{
+ return theModule->getURI();
+}
+
+void
+ImapFunction::getHostUserPassword(
+ const ExternalFunction::Arguments_t& aArgs,
+ int aPos,
+ std::string& aHost,
+ std::string& aUserName,
+ std::string& aPassword) const
+{
+ Item lNode;
+ Iterator_t args_iter = aArgs[aPos]->getIterator();
+ args_iter->open();
+ args_iter->next(lNode);
+ args_iter->close();
+ Iterator_t lChildren = lNode.getChildren();
+ lChildren->open();
+ Item lChild;
+ lChildren->next(lChild);
+ aHost = lChild.getStringValue().c_str();
+ lChildren->next(lChild);
+ aUserName = lChild.getStringValue().c_str();
+ lChildren->next(lChild);
+ aPassword = lChild.getStringValue().c_str();
+ lChildren->close();
+}
+
+String
+ImapFunction::getOneStringArg(
+ const ExternalFunction::Arguments_t& aArgs,
+ int aPos) const
+{
+ Item lItem;
+ Iterator_t args_iter = aArgs[aPos]->getIterator();
+ args_iter->open();
+ args_iter->next(lItem);
+ args_iter->close();
+ return lItem.getStringValue();
+}
+
+std::string
+ImapFunction::getMessageNumbers(
+ const ExternalFunction::Arguments_t& aArgs,
+ int aPos) const
+{
+ Item lItem;
+ std::stringstream lMessageNumbers;
+ Iterator_t args_iter = aArgs[aPos]->getIterator();
+ args_iter->open();
+ args_iter->next(lItem);
+ lMessageNumbers << lItem.getStringValue().c_str();
+ while(args_iter->next(lItem)) {
+ lMessageNumbers << "," << lItem.getStringValue().c_str();
+ }
+ args_iter->close();
+ return lMessageNumbers.str();
+}
+
+unsigned long
+ImapFunction::getOneMessageNumber(
+ const ExternalFunction::Arguments_t& aArgs,
+ int aPos) const
+{
+ Item lItem;
+ Iterator_t args_iter = aArgs[aPos]->getIterator();
+ args_iter->open();
+ args_iter->next(lItem);
+ args_iter->close();
+ return lItem.getLongValue();
+}
+
+bool
+ImapFunction::getOneBoolArg(
+ const ExternalFunction::Arguments_t& aArgs,
+ int aPos) const
+{
+ Item lItem;
+ Iterator_t args_iter = aArgs[aPos]->getIterator();
+ args_iter->open();
+ args_iter->next(lItem);
+ args_iter->close();
+ return lItem.getBooleanValue();
+}
+
+std::string
+ImapFunction::getDateTime(const std::string& aCClientDateTime) const
+{
+ std::stringstream lResult;
+ std::stringstream lDateTimeStream(aCClientDateTime);
+ std::string lBuffer;
+ std::vector<std::string> lTokens;
+
+ while (lDateTimeStream >> lBuffer) {
+ lTokens.push_back(lBuffer);
+ }
+
+ // build up map for Months
+ std::string lMonths = "JanFebMarAprMayJunJulAugSepOctNovDec";
+ size_t lMonthNumber = lMonths.find(lTokens[2]);
+ size_t lTokensShift = 0;
+ if (lMonthNumber == std::string::npos) {
+ // if the month is not there, day of week is possibly missing,
+ // shift tokens by one and retry
+ lTokensShift = -1;
+ lMonthNumber = lMonths.find(lTokens[2 + lTokensShift]);
+ if (lMonthNumber == std::string::npos) {
+ // now, we are really in trouble, something is wrong
+ Item lQName = theModule->getItemFactory()
+ ->createQName(SCHEMA_NAMESPACE, "XPTY0004");
+ throw USER_EXCEPTION(
+ lQName,
+ "Error while processing month in date of email message");
+ }
+ }
+
+ // YYYY-MM-DDThh:mm:ss, first push YYYY
+ lResult << lTokens[3 + lTokensShift] << "-";
+ // then push MM
+
+ lMonthNumber = lMonthNumber/3 + 1;
+ // make sure its MM and not just <
+ if (lMonthNumber < 10) {
+ lResult << 0;
+ }
+ lResult << lMonthNumber << "-";
+
+ if (lTokens[1 + lTokensShift].size() == 1) {
+ lResult << 0;
+ }
+ lResult << lTokens[1 + lTokensShift] << "T";
+ // now hh:mm:ss
+ lResult << lTokens[4 + lTokensShift].substr(0,2) << ":"
+ << lTokens[4 + lTokensShift].substr(3,2) << ":"
+ << lTokens[4 + lTokensShift].substr(6,2);
+
+
+ return lResult.str();
+
+}
+
+std::string
+ImapFunction::getContentType(
+ const unsigned short aType,
+ const char* aSubtype) const
+{
+ std::stringstream lType;
+ switch (aType) {
+ // Text
+ case 0 :
+ lType << "text";
+ break;
+ case 1 :
+ lType << "multipart";
+ break;
+ case 2 :
+ lType << "message";
+ break;
+ case 3 :
+ lType << "application";
+ break;
+ case 4 :
+ lType << "audio";
+ break;
+ case 5 :
+ lType << "image";
+ break;
+ case 6 :
+ lType << "video";
+ break;
+ case 7 :
+ lType << "model";
+ break;
+ case 8 :
+ lType << "other";
+ break;
+ }
+ std::string lSubType(aSubtype);
+ std::transform(lSubType.begin(), lSubType.end(), lSubType.begin(), tolower);
+ lType << "/" << lSubType;
+ return lType.str();
+
+}
+
+std::string
+ImapFunction::getEncoding(const unsigned short aEncoding) const
+{
+ std::stringstream lEncoding;
+ switch (aEncoding) {
+ case 0 :
+ lEncoding << "ENC7BIT";
+ break;
+ case 1 :
+ lEncoding << "ENC8BIT";
+ break;
+ case 2 :
+ lEncoding << "ENCBINARY";
+ break;
+ case 3 :
+ lEncoding << "ENCBASE64";
+ break;
+ case 4 :
+ lEncoding << "ENCQUOTEDPRINTABLE";
+ break;
+ case 5 :
+ lEncoding << "ENCOTHER";
+ break;
+ default : lEncoding << "ENCOTHER";
+
+
+ }
+ return lEncoding.str();
+}
+
+void
+ImapFunction::createFlagsNode(
+ Item& aParent,
+ Item& aFlags,
+ std::vector<int>& aFlagsVector,
+ const bool aQualified) const
+{
+ NsBindings ns_binding;
+ ns_binding.push_back(std::pair<String, String>(SCHEMA_PREFIX, SCHEMA_NAMESPACE));
+
+ // if aParent is null, then we want to have the flags node qualified (so that it can be shema validated)
+ Item lFlagsName;
+ lFlagsName = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, SCHEMA_PREFIX, "flags");
+ Item lFlagsType = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, "flagsType");
+ aFlags = theModule->getItemFactory()->createElementNode(aParent, lFlagsName, lFlagsType, false, false, ns_binding);
+
+ std::string lFlagName;
+ for (int i = 0; i < 5; ++i) {
+ int lFlagNumber = aFlagsVector[i];
+ if (lFlagNumber == 1) {
+ switch (i) {
+ case 0:
+ lFlagName = "seen";
+ break;
+ case 1 :
+ lFlagName = "deleted";
+ break;
+ case 2 :
+ lFlagName = "flagged";
+ break;
+ case 3 :
+ lFlagName = "answered";
+ break;
+ case 4 :
+ lFlagName = "draft";
+ break;
+ }
+
+ Item lOneFlagName = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, SCHEMA_PREFIX, lFlagName);
+ Item lOneFlagType = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, "emptyType");
+ Item lOneFlag = theModule->getItemFactory()->createElementNode(aFlags, lOneFlagName, lOneFlagType, false, true, ns_binding);
+ }
+ }
+}
+
+void
+ImapFunction::createInnerNodeWithText(
+ Item& aParent,
+ const std::string& aNamespace,
+ const std::string& aPrefix,
+ const std::string& aName,
+ const std::string& aTypeNamespace,
+ const std::string& aType,
+ const std::string& aContent) const
+{
+ NsBindings null_binding;
+ Item lName = theModule->getItemFactory()->createQName(aNamespace, aPrefix, aName);
+ Item lType = theModule->getItemFactory()->createQName(aTypeNamespace, aType);
+ Item lItem = theModule->getItemFactory()->createElementNode(aParent, lName, lType, false, false, null_binding);
+ theModule->getItemFactory()->createTextNode(lItem, String(aContent));
+}
+
+void
+ImapFunction::createContentNode(
+ Item& aParent,
+ const std::string& aContent,
+ const std::string& aContentType,
+ const std::string& aCharset,
+ const std::string& aContentTransferEncoding,
+ const std::string& aContentDisposition,
+ const std::string& aContentDispositionFilename,
+ const std::string& aContentDispositionModificationDate,
+ const std::string& aContentId) const
+{
+ Item lNullItem;
+
+ NsBindings null_binding;
+ Item lName = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, SCHEMA_PREFIX, "content");
+ Item lType = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, "contentType" );
+ Item lItem = theModule->getItemFactory()->createElementNode(aParent, lName, lType, false, false, null_binding);
+
+ createContentTypeAttributes(lItem, aContentType, aCharset, aContentTransferEncoding, aContentDisposition, aContentDispositionFilename, aContentDispositionModificationDate);
+
+ if (aContentId.length() > 1) {
+ Item lContentIdName = theModule->getItemFactory()->createQName("", "content-id");
+ Item lContentIdType = theModule->getItemFactory()->createQName("http://www.w3.org/2001/XMLSchema";, "string");
+ Item lContentIdText = theModule->getItemFactory()->createTextNode(lNullItem, String(aContentId));
+ theModule->getItemFactory()->createAttributeNode(lItem, lContentIdName, lContentIdType, lContentIdText);
+ }
+
+ theModule->getItemFactory()->createTextNode(lItem, String(aContent));
+}
+
+void
+ImapFunction::createEmailAddressNode(
+ Item& aParent,
+ const std::string& aName,
+ const char* aPersonal,
+ const char* aMailbox,
+ const char* aHost) const
+{
+ if ((aMailbox) && (aHost)) {
+ // mailbox and host needs to be available, otherwise broken
+ Item lType = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, "emailAddress");
+ Item lName = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, SCHEMA_PREFIX, aName);
+
+ NsBindings ns_binding;
+ ns_binding.push_back(std::pair<String, String>(SCHEMA_PREFIX, SCHEMA_NAMESPACE));
+
+ Item lItem = theModule->getItemFactory()->createElementNode(aParent, lName, lType, false, false, ns_binding);
+ if (aPersonal) {
+ std::string lDecodedPersonal;
+ decodeHeader(std::string(aPersonal), lDecodedPersonal);
+ createInnerNodeWithText(
+ lItem, SCHEMA_NAMESPACE, SCHEMA_PREFIX, "name",
+ "http://www.w3.org/2001/XMLSchema";, "string", lDecodedPersonal);
+ }
+
+ std::string lDecodedMailbox, lDecodedHost;
+ decodeHeader(std::string(aMailbox), lDecodedMailbox);
+ decodeHeader(std::string(aHost), lDecodedHost);
+ createInnerNodeWithText(
+ lItem, SCHEMA_NAMESPACE, SCHEMA_PREFIX, "email", SCHEMA_NAMESPACE,
+ "emailAddressType", lDecodedMailbox + "@" + lDecodedHost);
+ }
+}
+
+void
+ImapFunction::createRecipientNode(
+ Item& aParent,
+ const std::string& aName,
+ const char* aPersonal,
+ const char* aMailbox,
+ const char* aHost) const
+{
+ if (aMailbox && aHost) {
+ // mailbox and host needs to be available, otherwise bcc
+ Item lType = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, "recipientType");
+ Item lName = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, SCHEMA_PREFIX, "recipient");
+
+ NsBindings ns_binding;
+ ns_binding.push_back(std::pair<String, String>(SCHEMA_PREFIX, SCHEMA_NAMESPACE));
+
+ Item lItem = theModule->getItemFactory()->createElementNode(aParent, lName, lType, false, false, ns_binding);
+ createEmailAddressNode(lItem, aName, aPersonal, aMailbox, aHost);
+ }
+}
+
+void
+ImapFunction::createContentTypeAttributes(
+ Item& aParent,
+ const std::string& aContentType,
+ const std::string& aCharset,
+ const std::string& aContentTransferEncoding,
+ const std::string& aContentDisposition,
+ const std::string& aContentDispositionFilename,
+ const std::string& aContentDispositionModificationDate) const
+{
+ Item lNullItem;
+ /* build the value attribute */
+ Item lContentTypeName = theModule->getItemFactory()->createQName("", "contentType");
+ Item lContentTypeType = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, "contentTypeValue");
+ Item lContentTypeText = theModule->getItemFactory()->createTextNode(lNullItem, String(aContentType));
+ theModule->getItemFactory()->createAttributeNode(aParent, lContentTypeName, lContentTypeType, lContentTypeText);
+
+ /* build the charset attribute */
+ Item lCharsetName = theModule->getItemFactory()->createQName("", "charset");
+ Item lCharsetType = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, "string");
+ Item lCharsetText = theModule->getItemFactory()->createTextNode(lNullItem, String(aCharset));
+ theModule->getItemFactory()->createAttributeNode(aParent, lCharsetName, lCharsetType, lCharsetText);
+
+ /* build the contentTransferEncoding attribute */
+ Item lContentTransferName = theModule->getItemFactory()->createQName("", "contentTransferEncoding");
+ Item lContentTransferType = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, "cteType");
+ Item lContentTransferText = theModule->getItemFactory()->createTextNode(lNullItem, String(aContentTransferEncoding));
+ theModule->getItemFactory()->createAttributeNode(aParent, lContentTransferName, lContentTransferType, lContentTransferText);
+ /* build the contentDisposition attribute */
+
+ if (aContentDisposition.length() > 2) {
+
+ Item lContentDispositionName = theModule->getItemFactory()->createQName("", "contentDisposition");
+ Item lContentDispositionType = theModule->getItemFactory()->createQName("http://www.w3.org/2001/XMLSchema";, "string");
+ Item lContentDispositionText = theModule->getItemFactory()->createTextNode(lNullItem, String(aContentDisposition));
+ theModule->getItemFactory()->createAttributeNode(aParent, lContentDispositionName, lContentDispositionType, lContentDispositionText);
+ if (aContentDispositionFilename.length() > 1) {
+ /* build the contentDispositionFilename attribute */
+ Item lContentDispositionFilenameName = theModule->getItemFactory()->createQName("", "contentDisposition-filename");
+ Item lContentDispositionFilenameType = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, "string");
+ Item lContentDispositionFilenameText = theModule->getItemFactory()->createTextNode(lNullItem, String(aContentDispositionFilename));
+ theModule->getItemFactory()->createAttributeNode(aParent, lContentDispositionFilenameName, lContentDispositionFilenameType, lContentDispositionFilenameText);
+ }
+ if (aContentDispositionModificationDate.length() > 2) {
+ /* build the contentDispositionModificationDate attribute */
+ Item lContentDispositionModificationDateName = theModule->getItemFactory()->createQName("", "contentDisposition-modification-date");
+ Item lContentDispositionModificationDateType = theModule->getItemFactory()->createQName("http://www.w3.org/2001/XMLSchema";, "string");
+ Item lContentDispositionModificationDateText = theModule->getItemFactory()->createTextNode(lNullItem, String(getDateTime(aContentDispositionModificationDate)));
+ theModule->getItemFactory()->createAttributeNode(aParent, lContentDispositionModificationDateName, lContentDispositionModificationDateType, lContentDispositionModificationDateText);
+ }
+ }
+}
+
+void
+ImapFunction::getMessage(
+ Item& aParent,
+ const std::string& aHostName,
+ const std::string& aUserName,
+ const std::string& aPassword,
+ const std::string& aMailbox,
+ const unsigned long aMessageNumber,
+ const bool aUid,
+ const bool aOnlyEnvelope) const
+{
+ std::vector<int> lFlags(6,0);
+ ENVELOPE* lEnvelope;
+ BODY* lBody;
+ if (aOnlyEnvelope) {
+ // only fetch envelope
+ lEnvelope = ImapClient::Instance().fetchEnvelope(aHostName, aUserName, aPassword, aMailbox, aMessageNumber, lFlags, aUid);
+ } else {
+ // the flags vector in the imap client will be filled by this call, so clear it
+ lEnvelope = ImapClient::Instance().fetchStructure(aHostName, aUserName, aPassword, aMailbox, &lBody, aMessageNumber, aUid, lFlags);
+ }
+
+ NsBindings ns_binding;
+ ns_binding.push_back(std::pair<String, String>(SCHEMA_PREFIX, SCHEMA_NAMESPACE));
+
+ Item lEnvelopeItem;
+ std::string lErrorMessage = ImapClient::Instance().getError();
+ if (lErrorMessage.size() != 0) {
+ Item lQName = ImapModule::getItemFactory()->createQName(ImapModule::getURIString(), "imap", "IMAP0001");
+ throw USER_EXCEPTION(lQName, lErrorMessage);
+ }
+
+ // First construct the envelope (depending on aOnlyEnvelope we may be finished then)
+ // Important: if we only want the envelope, then the envelope MUST be qualified (being the root of the DOM)
+ Item lEnvelopeName;
+ if (aOnlyEnvelope) {
+ lEnvelopeName = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, SCHEMA_PREFIX, "envelope");
+ } else {
+ lEnvelopeName = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, SCHEMA_PREFIX, "envelope");
+ }
+ Item lEnvelopeType = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, SCHEMA_PREFIX, "envelopeType");
+
+ Item lNullItem;
+ // if we only want the envelope, then create it with a null parent, else create the message and use it as parent
+ if (aOnlyEnvelope) {
+ lEnvelopeItem = theModule->getItemFactory()->createElementNode(lNullItem, lEnvelopeName, lEnvelopeType, false, false, ns_binding);
+ } else {
+ Item lMessageName = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, SCHEMA_PREFIX, "message");
+ Item lMessageType = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, SCHEMA_PREFIX, "messageType");
+ aParent = theModule->getItemFactory()->createElementNode(lNullItem, lMessageName, lMessageType, false, false, ns_binding);
+ lEnvelopeItem = theModule->getItemFactory()->createElementNode(aParent, lEnvelopeName, lEnvelopeType, false, false, ns_binding);
+ }
+
+ // create the remail node if needed
+ if (lEnvelope->remail) {
+ std::string lDecodedRemail;
+ decodeHeader(std::string(lEnvelope->remail), lDecodedRemail);
+ createInnerNodeWithText(
+ lEnvelopeItem, SCHEMA_NAMESPACE, SCHEMA_PREFIX, "remail",
+ "http://www.w3.org/2001/XMLSchema";, "string", lDecodedRemail);
+ }
+ // create the date node if needed
+ if (lEnvelope->date) {
+ createInnerNodeWithText(
+ lEnvelopeItem,
+ SCHEMA_NAMESPACE,
+ SCHEMA_PREFIX,
+ "date",
+ "http://www.w3.org/2001/XMLSchema";,
+ "string",
+ getDateTime(reinterpret_cast<const char*>(lEnvelope->date)));
+ }
+ // create from node if needed
+ if (lEnvelope->from) {
+ createEmailAddressNode(lEnvelopeItem, "from", lEnvelope->from->personal, lEnvelope->from->mailbox, lEnvelope->from->host);
+ }
+ // create sender node if needed
+ if (lEnvelope->sender) {
+ createEmailAddressNode(lEnvelopeItem, "sender", lEnvelope->sender->personal, lEnvelope->sender->mailbox, lEnvelope->sender->host);
+ }
+ // create replyTo node if needed
+ if (lEnvelope->reply_to) {
+ createEmailAddressNode(lEnvelopeItem, "replyTo", lEnvelope->reply_to->personal, lEnvelope->reply_to->mailbox, lEnvelope->reply_to->host);
+ }
+ // create subject node
+ if (lEnvelope->subject) {
+ std::string lSubject = lEnvelope->subject;
+ std::string lDecodedSubject;
+ decodeHeader(lSubject, lDecodedSubject);
+ createInnerNodeWithText(lEnvelopeItem, SCHEMA_NAMESPACE, SCHEMA_PREFIX, "subject", "http://www.w3.org/2001/XMLSchema";, "string", lDecodedSubject);
+ }
+
+ ADDRESS* lRecipients;
+ if (lEnvelope->to) {
+ createRecipientNode(lEnvelopeItem, "to", lEnvelope->to->personal, lEnvelope->to->mailbox, lEnvelope->to->host);
+ lRecipients = lEnvelope->to;
+ while ((lRecipients = lRecipients->next)) {
+ createRecipientNode(lEnvelopeItem, "to", lEnvelope->to->personal, lEnvelope->to->mailbox, lEnvelope->to->host);
+ }
+ }
+
+ if (lEnvelope->cc) {
+ createRecipientNode(lEnvelopeItem, "cc", lEnvelope->cc->personal, lEnvelope->cc->mailbox, lEnvelope->cc->host);
+ lRecipients = lEnvelope->cc;
+ while ((lRecipients = lRecipients->next)) {
+ createRecipientNode(lEnvelopeItem, "cc", lEnvelope->cc->personal, lEnvelope->cc->mailbox, lEnvelope->cc->host);
+ }
+ }
+
+ if ((lRecipients = lEnvelope->bcc)) {
+ createRecipientNode(lEnvelopeItem, "bcc", lEnvelope->bcc->personal, lEnvelope->bcc->mailbox, lEnvelope->bcc->host);
+ while ((lRecipients = lRecipients->next)) {
+ createRecipientNode(lEnvelopeItem, "bcc", lEnvelope->bcc->personal, lEnvelope->bcc->mailbox, lEnvelope->bcc->host);
+ }
+ }
+
+ // create messageId node
+ if (lEnvelope->message_id) {
+ createInnerNodeWithText(lEnvelopeItem, SCHEMA_NAMESPACE, SCHEMA_PREFIX, "messageId", "http://www.w3.org/2001/XMLSchema";, "string", lEnvelope->message_id);
+ }
+ Item lFlagsItem;
+ // create flags node
+ createFlagsNode(lEnvelopeItem, lFlagsItem, lFlags, false);
+
+ // if we only want the envelope, then here is a good place to stop
+ if (aOnlyEnvelope) {
+ aParent = lEnvelopeItem;
+ return;
+ }
+
+ // if we want the whole message, then build it together
+
+ // <email:mimeVersion>1.0</email:mimeVersion>
+ createInnerNodeWithText(aParent, SCHEMA_NAMESPACE, SCHEMA_PREFIX, "mimeVersion", "http://www.w3.org/2001/XMLSchema";, "string", "1.0");
+
+ // make a tolower version of the subtype
+ std::string lSubType(lBody->subtype);
+ std::transform(lSubType.begin(), lSubType.end(), lSubType.begin(), tolower);
+
+ // creating the <body> node
+ Item lBodyName = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, SCHEMA_PREFIX, "body");
+ Item lBodyType = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, SCHEMA_PREFIX, "bodyTypeChoice");
+ Item lBodyItem = theModule->getItemFactory()->createElementNode(aParent, lBodyName, lBodyType, false, false, ns_binding);
+ // in case of non-multipart, just add the body to the message
+
+ Item lMultipartParentName = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, SCHEMA_PREFIX, "multipart");
+ Item lMultipartParentType = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, SCHEMA_PREFIX, "multipartType");
+ Item lMultipartParent;
+ // using a vector instead of a stack, because including stack will clash with the c-client include ...
+ std::vector<BODY*> lBodies;
+ lBodies.push_back(lBody);
+ std::vector<Item> lParents;
+ lParents.push_back(lBodyItem);
+ std::vector<std::string> lSections;
+ lSections.push_back("");
+
+ // make sure that the special case of a completely non-multipart message is handled correctly
+ bool lNoMultipart = false;
+ if (lBody->type != TYPEMULTIPART) {
+ lNoMultipart = true;
+ }
+
+ BODY* lCurrentBody;
+ Item lCurrentParent;
+ std::string lCurrentSection;
+ // iterate and create all nodes (doing this recursive would have been nicer, but seems impossible without making a function containing a c-client structure in its signature, which seems impossible)
+ while (lBodies.size() > 0) {
+ lCurrentBody = lBodies.front();
+ lCurrentParent = lParents.front();
+ lCurrentSection = lSections.front();
+ lSections.erase(lSections.begin());
+ lParents.erase(lParents.begin());
+ lBodies.erase(lBodies.begin());
+ // get different attributes that we will need in any case, regardless if this is a content or multipart item
+ std::string lContentType = getContentType(lCurrentBody->type, lCurrentBody->subtype);
+ std::string lContentDisposition = "";
+ if (lCurrentBody->disposition.type != NIL) {
+ lContentDisposition = cpystr(lCurrentBody->disposition.type);
+ }
+ std::string lContentDispositionFilename = "";
+ std::string lContentDispositionModificationDate = "";
+
+ PARAMETER* lCurrentParameter = lCurrentBody->disposition.parameter;
+ while (lCurrentParameter != NIL) {
+ std::string lAttribute = lCurrentParameter->attribute;
+ std::transform(lAttribute.begin(), lAttribute.end(), lAttribute.begin(), ::tolower);
+ if (!std::string("filename").compare(lAttribute)) {
+ lContentDispositionFilename = cpystr(lCurrentParameter->value);
+ } else if (!std::string("filename*0").compare(lAttribute)) {
+ // TODO this is a hack that works for most cases.
+ // See: http://tools.ietf.org/html/rfc2184 [Page 3]
+ lContentDispositionFilename = cpystr(lCurrentParameter->value);
+ } else if (!std::string("modification-date").compare(lAttribute)) {
+ lContentDispositionModificationDate = cpystr(lCurrentParameter->value);
+ }
+
+ lCurrentParameter = lCurrentParameter->next;
+ }
+
+ if (lCurrentBody->type != TYPEMULTIPART) {
+ std::string lContentId = "";
+ char * lId = lCurrentBody->id;
+
+ if (lId != NIL) {
+ lContentId = cpystr(lId);
+ }
+
+ std::string lSubType(lCurrentBody->subtype);
+ std::transform(lSubType.begin(), lSubType.end(), lSubType.begin(), tolower);
+ // make sure that we haven't got a empty string (happens if there is no multipart in this message)
+ if (lCurrentSection.size() != 0) {
+ lCurrentSection.erase(lCurrentSection.end() - 1);
+ }
+
+ std::string lBodyContent = ImapClient::Instance().fetchBodyFull(aHostName, aUserName, aPassword, aMailbox, aMessageNumber, lNoMultipart ? "1" : lCurrentSection, aUid);
+
+ // reading charset from email
+ // default mime charset, see
+ // http://tools.ietf.org/html/draft-ietf-appsawg-mime-default-charset-04
+ std::string lCharset = "ISO-8859-1";
+ PARAMETER* lParam = lCurrentBody->parameter;
+ while (lParam) {
+ std::string lAttribute = lParam->attribute;
+ std::transform(lAttribute.begin(), lAttribute.end(), lAttribute.begin(), ::tolower);
+ if (lAttribute.compare("charset") == 0) {
+ lCharset = lParam->value;
+ }
+ lParam = lParam->next;
+ }
+
+ std::string lTransferEncodingDecoded;
+ unsigned short lEncoding = lCurrentBody->encoding;
+ // decode the body according the transfer encoding if it is quoted-printable
+ decodeTextualTransferEncoding(lBodyContent, lContentType, lEncoding, lTransferEncodingDecoded);
+
+ // decode the body according to the charset
+ std::string lCharsetDecoded;
+ toUtf8(lTransferEncodingDecoded, lCharset, lCharsetDecoded);
+
+ createContentNode(lCurrentParent, lCharsetDecoded, lContentType,
+ "utf-8", getEncoding(lEncoding), lContentDisposition,
+ lContentDispositionFilename, lContentDispositionModificationDate,
+ lContentId);
+
+ } else {
+ lMultipartParent = theModule->getItemFactory()->createElementNode(
+ lCurrentParent, lMultipartParentName, lMultipartParentType, false,
+ false, ns_binding);
+
+ createContentTypeAttributes(lMultipartParent, lContentType, "utf-8",
+ getEncoding(lCurrentBody->encoding), lContentDisposition,
+ lContentDispositionFilename, lContentDispositionModificationDate);
+
+ PART* lPart = lCurrentBody->nested.part;
+ lBodies.insert(lBodies.begin(), &lPart->body);
+ lParents.insert(lParents.begin(), lMultipartParent);
+ lSections.insert(lSections.begin(), lCurrentSection + "1.");
+ for (int j = 1; lPart->next; ++j) {
+ lPart = lPart->next;
+ std::stringstream lConverter;
+ lConverter << j+1 << ".";
+ lSections.insert(lSections.begin() + j, lCurrentSection + lConverter.str());
+ lConverter.clear();
+ lBodies.insert(lBodies.begin() +j, &lPart->body);
+ lParents.insert(lParents.begin(), lMultipartParent);
+ }
+ }
+ }
+}
+
+void
+ImapFunction::toUtf8(
+ const std::string& aValue,
+ const std::string& aFromCharset,
+ std::string& aResult) const
+{
+ if (aFromCharset == "") {
+ aResult = aValue;
+ return;
+ }
+
+ // transforming the body from the declared charset to utf-8
+ const char* lValueChar = aValue.c_str();
+ // TODO array auto ptr
+ UChar* lUnicodeBody = new UChar[aValue.length()+1];
+ UErrorCode lStatus = U_ZERO_ERROR;
+ UConverter *lConverter;
+
+ // set up the converter
+ lConverter = ucnv_open(aFromCharset.c_str(), &lStatus);
+ checkStatus(lStatus);
+
+ // convert to Unicode
+ int32_t lUnicodeLen = ucnv_toUChars(
+ lConverter,
+ lUnicodeBody,
+ aValue.length()+1,
+ lValueChar,
+ -1,
+ &lStatus);
+ checkStatus(lStatus);
+
+ int32_t lUTF8Memory = lUnicodeLen*4 + 1;
+ // TODO autoptr
+ char* lUTF8Body = new char[lUTF8Memory];
+ int32_t lUTF8Len;
+
+ //convert from unicode to UTF8
+ u_strToUTF8(lUTF8Body,
+ lUTF8Memory,
+ &lUTF8Len,
+ lUnicodeBody,
+ -1,
+ &lStatus);
+ checkStatus(lStatus);
+
+ aResult = lUTF8Body;
+}
+
+
+void
+ImapFunction::checkStatus(UErrorCode aStatus) const
+{
+ if (!U_SUCCESS(aStatus)) {
+ std::stringstream lStream;
+ lStream << "Failed to convert email fragment (subject or body) to UTF-8. ICU error code: " << u_errorName(aStatus) << ".";
+ raiseImapError("IMAP0001", lStream.str());
+ }
+}
+
+struct PrintableAsciiChar
+{
+ bool operator()(char c) const {
+ unsigned int u = static_cast<unsigned int>(c);
+ return !(u == '\t' || u == '\n' || u == '\t' || (u >= 32 && u <= 127));
+ }
+};
+
+void
+ImapFunction::decodeHeader(
+ const std::string& aValue,
+ std::string& aResult) const
+{
+ std::string lValue = aValue;
+ // We assume that email headers must not contain non-printable characters
+ // because special chars need to be encoded.
+ // Therefore, we filter everything non-printable out to avoid problems.
+ lValue.erase(
+ std::remove_if(
+ lValue.begin(),
+ lValue.end(),
+ PrintableAsciiChar()),
+ lValue.end()
+ );
+
+ std::stringstream lDecoded;
+ std::size_t lMarker = 0;
+
+ // size used many times
+ std::size_t lLength = lValue.length();
+ // to collect question mark positions
+ std::vector<std::size_t> lQMs;
+
+ // populate the above vectors
+ for (std::size_t i = 0; i < lLength; i++) {
+ if (lValue.at(i) == '?') {
+ lQMs.push_back(i);
+ }
+ }
+
+ // sizes we need below
+ std::size_t lQLength = lQMs.size();
+
+ // not enough questions marks to make up an encoding, give up
+ if (lQLength < 4) {
+ aResult = lValue;
+ return;
+ }
+
+ // now we take groups of 4 question marks
+ for (std::size_t j = 0; j <= lQLength - 4; ) {
+ // a good encoding meets these conditions:
+ if (
+ // 2nd and 3rd question marks have only one character in between
+ lQMs[j + 1] + 2 == lQMs[j + 2] &&
+ // 1st question mark is prefixed by an equal sign
+ (lQMs[j] > 0 && lValue.at(lQMs[j] - 1) == '=') &&
+ // 4th question mark is suffixes by an equal sign
+ (lQMs[j + 3] < (lLength-1) && lValue.at(lQMs[j + 3] + 1) == '='))
+ {
+ // ok were good, so first save the text from the last marker
+ // upto the starting equal sign
+ lDecoded << lValue.substr(lMarker, lQMs[j] - lMarker - 1);
+
+ // then take the entire region, including =? and ?= and try to decode it
+ std::string lWords;
+ decodeEncodedWords(lValue.substr(lQMs[j] - 1, lQMs[j + 3] - lQMs[j] + 3), lWords);
+ lDecoded << lWords;
+
+ // save the new marker at the end of this encoded word group
+ lMarker = lQMs[j + 3] + 2;
+
+ // decoding with the current 4 question marks worked well so we skip them and try the next 4
+ j += 4;
+ }
+ else {
+ // not a valid encoding, so iterate to the next question mark
+ ++j;
+ }
+ }
+ lDecoded << lValue.substr(lMarker);
+
+ aResult = lDecoded.str();
+}
+
+bool isTextOrXMLContentType(const std::string& aContentType) {
+ return aContentType.find("text/") != std::string::npos
+ || aContentType == "application/xml"
+ || aContentType.find("+xml") != std::string::npos;
+}
+
+void
+ImapFunction::decodeTextualTransferEncoding(
+ const std::string& aValue,
+ const std::string& aContentType,
+ unsigned short& aEncoding,
+ std::string& aResult) const
+{
+ if (aEncoding == ENCQUOTEDPRINTABLE) {
+ unsigned long lNewLength;
+ void* lNewData = rfc822_qprint((unsigned char*)aValue.c_str(), aValue.length(), &lNewLength);
+ aResult = std::string((char *)lNewData, lNewLength);
+ fs_give(&lNewData);
+ aEncoding = ENC8BIT;
+ if (!isTextOrXMLContentType(aContentType)) {
+ // binary content needs to be base64 encoded for zorba
+ std::string lOutput;
+ zorba::base64::encode(aResult, &lOutput);
+ aResult = lOutput;
+ }
+ }
+ else if (aEncoding == ENCBASE64) {
+ aResult = aValue;
+ // remove newlines from base64
+ aResult.erase(std::remove(aResult.begin(), aResult.end(), '\r'), aResult.end());
+ aResult.erase(std::remove(aResult.begin(), aResult.end(), '\n'), aResult.end());
+ if (isTextOrXMLContentType(aContentType))
+ {
+ unsigned long lNewLength;
+ void* lNewData = rfc822_base64((unsigned char*)aResult.c_str(), aResult.length(), &lNewLength);
+ aResult = std::string((char *)lNewData, lNewLength);
+ fs_give(&lNewData);
+ aEncoding = ENC8BIT;
+ }
+ }
+ else
+ {
+ aResult = aValue;
+ }
+}
+
+} /* namespace emailmodule */
+} /* namespace zorba */
=== added file 'src/com/zorba-xquery/www/modules/email/imap.xq.src/imap_function.h'
--- src/com/zorba-xquery/www/modules/email/imap.xq.src/imap_function.h 1970-01-01 00:00:00 +0000
+++ src/com/zorba-xquery/www/modules/email/imap.xq.src/imap_function.h 2014-04-30 23:07:12 +0000
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ZORBA_EMAILMODULE_IMAPFUNCTION_H
+#define ZORBA_EMAILMODULE_IMAPFUNCTION_H
+
+#include <string>
+
+#include <zorba/function.h>
+#include <zorba/error.h>
+
+#include <unicode/utypes.h>
+
+
+namespace zorba { namespace emailmodule {
+
+class ImapModule;
+class EmailException;
+
+class ImapFunction : public ContextualExternalFunction
+{
+ protected:
+ const ImapModule* theModule;
+ static const char* SCHEMA_NAMESPACE;
+ static const char* SCHEMA_PREFIX;
+
+ void
+ raiseImapError(
+ EmailException& e) const;
+
+ void
+ raiseImapError(
+ const std::string& qName,
+ const std::string& message) const;
+
+ void
+ getHostUserPassword(
+ const ExternalFunction::Arguments_t& aArgs,
+ int aPos,
+ std::string& aHost,
+ std::string& aUserName,
+ std::string& aPassword) const;
+
+ String
+ getOneStringArg(
+ const ExternalFunction::Arguments_t& args,
+ int pos) const;
+
+ std::string
+ getMessageNumbers(
+ const ExternalFunction::Arguments_t& args,
+ int pos) const;
+
+ unsigned long
+ getOneMessageNumber(
+ const ExternalFunction::Arguments_t& args,
+ int pos) const;
+
+ bool
+ getOneBoolArg(
+ const ExternalFunction::Arguments_t& args,
+ int pos) const;
+
+ /*
+ * Converts a dateTime string as returned by the c-client (e.g. Tue, 24
+ * Aug 2010 16:26:10 +0200'DD) into a xs:dateTime format.
+ */
+ std::string
+ getDateTime(const std::string& aCClientDateTime) const;
+
+ std::string
+ getContentType(const unsigned short aType, const char* aSubtype) const;
+
+ std::string
+ getEncoding(const unsigned short aEncoding) const;
+
+ void
+ createFlagsNode(
+ Item& aParent,
+ Item& aFlags,
+ std::vector<int>& aFlagsVector,
+ const bool aQualified) const;
+
+ /*
+ * Creates a simple named node containing a text node.
+ */
+ void
+ createInnerNodeWithText(
+ Item& aParent,
+ const std::string& aNamespace,
+ const std::string& aPrefix,
+ const std::string& aName,
+ const std::string& aTypeNamespace,
+ const std::string& aType,
+ const std::string& aContent) const;
+
+ void
+ createContentNode(
+ Item& aParent,
+ const std::string& aContent,
+ const std::string& contentType,
+ const std::string& charset,
+ const std::string& contentTransferEncoding,
+ const std::string& aContentDisposition,
+ const std::string& aContentDispositionFilename,
+ const std::string& aContentDispositionModificationDate,
+ const std::string& aContentId) const;
+
+ /*
+ * Creates a simple email address node as defined in email.xsd
+ */
+ void
+ createEmailAddressNode(
+ Item& aParent,
+ const std::string& aName,
+ const char * aPersonal,
+ const char* aMailbox,
+ const char* aHost) const;
+
+ void
+ createRecipientNode(
+ Item& aParent,
+ const std::string& aName,
+ const char* aPersonal,
+ const char* aMailbox,
+ const char* aHost) const;
+
+ void
+ createContentTypeAttributes(
+ Item& aParent,
+ const std::string& aValue,
+ const std::string& aCharset,
+ const std::string& aTransferEncoding,
+ const std::string& aContentDisposition,
+ const std::string& aContentDispositionFilename,
+ const std::string& aContentDispositionModificationDate) const;
+
+ void
+ getMessage(
+ Item& aParent,
+ const std::string& aHostName,
+ const std::string& aUserName,
+ const std::string& aPassword,
+ const std::string& aMailbox,
+ const unsigned long aMessageNumber,
+ const bool aUid,
+ const bool aOnlyEnvelope) const;
+
+ void
+ decodeTextualTransferEncoding(const std::string& aValue,
+ const std::string& aContentType,
+ unsigned short& aEncoding,
+ std::string& aResult) const;
+
+ void
+ toUtf8(
+ const std::string& value,
+ const std::string& fromCharset,
+ std::string& result) const;
+
+ void
+ checkStatus(UErrorCode aStatus) const;
+
+ /**
+ * Decodes header of an email, e.g. the subject.
+ */
+ void
+ decodeHeader(
+ const std::string& value,
+ std::string& result) const;
+
+ // This function is defined in imap.cpp because if defined in imap_function.cpp
+ // some header file conflict are raised and it does not compile
+ void
+ decodeEncodedWords(
+ const std::string& value,
+ std::string& result) const;
+
+ public:
+ ImapFunction(const ImapModule* module);
+ ~ImapFunction();
+
+ virtual String
+ getURI() const;
+
+};
+
+} /* namespace emailmodule */
+} /* namespace zorba */
+
+#endif /* ZORBA_EMAILMODULE_IMAPFUNCTION_H */
=== added file 'src/com/zorba-xquery/www/modules/email/imap.xq.src/imap_module.cpp'
--- src/com/zorba-xquery/www/modules/email/imap.xq.src/imap_module.cpp 1970-01-01 00:00:00 +0000
+++ src/com/zorba-xquery/www/modules/email/imap.xq.src/imap_module.cpp 2014-04-30 23:07:12 +0000
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "imap.h"
+#include "imap_module.h"
+#include "imap_function.h"
+
+namespace zorba { namespace emailmodule {
+
+ ItemFactory* ImapModule::theFactory = 0;
+
+
+ImapModule::~ImapModule()
+{
+ for (FuncMap_t::const_iterator lIter = theFunctions.begin();
+ lIter != theFunctions.end(); ++lIter) {
+ delete lIter->second;
+ }
+ theFunctions.clear();
+}
+
+ExternalFunction*
+ImapModule::getExternalFunction(const String& aLocalname)
+{
+ ExternalFunction*& lFunc = theFunctions[aLocalname];
+ if (!lFunc) {
+ if (1 == 0) {
+ } else if (aLocalname == "status-impl") {
+ lFunc = new StatusFunction(this);
+ } else if (aLocalname == "create-impl") {
+ lFunc = new CreateFunction(this);
+ } else if (aLocalname == "delete-impl") {
+ lFunc = new DeleteFunction(this);
+ } else if (aLocalname == "rename-impl") {
+ lFunc = new RenameFunction(this);
+ } else if (aLocalname == "list-impl") {
+ lFunc = new ListFunction(this);
+ } else if (aLocalname == "subscribe-impl") {
+ lFunc = new SubscribeFunction(this);
+ } else if (aLocalname == "unsubscribe-impl") {
+ lFunc = new UnsubscribeFunction(this);
+ } else if (aLocalname == "expunge-impl") {
+ lFunc = new ExpungeFunction(this);
+ } else if (aLocalname == "search-impl") {
+ lFunc = new SearchFunction(this);
+ } else if (aLocalname == "copy-impl") {
+ lFunc = new CopyFunction(this);
+ } else if (aLocalname == "fetch-envelope-impl") {
+ lFunc = new FetchEnvelopeFunction(this);
+ } else if (aLocalname == "fetch-message-impl") {
+ lFunc = new FetchMessageFunction(this);
+ } else if (aLocalname == "fetch-subject-impl") {
+ lFunc = new FetchSubjectFunction(this);
+ } else if (aLocalname == "fetch-from-impl") {
+ lFunc = new FetchFromFunction(this);
+ } else if (aLocalname == "fetch-uid-impl") {
+ lFunc = new FetchUidFunction(this);
+ } else if (aLocalname == "fetch-message-sequence-number-impl") {
+ lFunc = new FetchMessageSequenceNumberFunction(this);
+ } else if (aLocalname == "fetch-flags-impl") {
+ lFunc = new FetchFlagsFunction(this);
+ } else if (aLocalname == "set-flags-impl") {
+ lFunc = new SetFlagsFunction(this);
+ }
+ }
+ return lFunc;
+}
+
+void
+ImapModule::destroy()
+{
+ if (!dynamic_cast<ImapModule*>(this)) {
+ return;
+ }
+ delete this;
+}
+
+} /* namespace emailmodule */ } /* namespace zorba */
=== added file 'src/com/zorba-xquery/www/modules/email/imap.xq.src/imap_module.h'
--- src/com/zorba-xquery/www/modules/email/imap.xq.src/imap_module.h 1970-01-01 00:00:00 +0000
+++ src/com/zorba-xquery/www/modules/email/imap.xq.src/imap_module.h 2014-04-30 23:07:12 +0000
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ZORBA_EMAILMODULE_IMAPMODULE_H
+#define ZORBA_EMAILMODULE_IMAPMODULE_H
+
+#include <map>
+
+#include <zorba/zorba.h>
+#include <zorba/external_module.h>
+
+namespace zorba { namespace emailmodule {
+
+class ImapModule : public ExternalModule
+{
+ private:
+ static ItemFactory* theFactory;
+
+ protected:
+ class ltstr
+ {
+ public:
+ bool operator()(const String& s1, const String& s2) const
+ {
+ return s1.compare(s2) < 0;
+ }
+ };
+
+ typedef std::map<String, ExternalFunction*, ltstr> FuncMap_t;
+
+ FuncMap_t theFunctions;
+
+ public:
+ virtual ~ImapModule();
+
+ virtual String
+ getURI() const { return ImapModule::getURIString(); }
+
+ virtual ExternalFunction*
+ getExternalFunction(const String& aLocalname);
+
+ virtual void
+ destroy();
+
+ static ItemFactory*
+ getItemFactory()
+ {
+ if(!theFactory)
+ {
+ theFactory = Zorba::getInstance(0)->getItemFactory();
+ }
+
+ return theFactory;
+ }
+
+ static String
+ getURIString() {
+ static String lURI = "http://www.zorba-xquery.com/modules/email/imap";;
+ return lURI;
+ }
+};
+
+
+} /* namespace emailmodule */
+} /* namespace zorba */
+
+#endif /* ZORBA_EMAILMODULE_IMAPMODULE_H */
=== added file 'src/com/zorba-xquery/www/modules/email/smtp.xq'
--- src/com/zorba-xquery/www/modules/email/smtp.xq 1970-01-01 00:00:00 +0000
+++ src/com/zorba-xquery/www/modules/email/smtp.xq 2014-04-30 23:07:12 +0000
@@ -0,0 +1,97 @@
+xquery version "3.0";
+
+(:
+ : Copyright 2006-2009 The FLWOR Foundation.
+ :
+ : Licensed under the Apache License, Version 2.0 (the "License");
+ : you may not use this file except in compliance with the License.
+ : You may obtain a copy of the License at
+ :
+ : http://www.apache.org/licenses/LICENSE-2.0
+ :
+ : Unless required by applicable law or agreed to in writing, software
+ : distributed under the License is distributed on an "AS IS" BASIS,
+ : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ : See the License for the specific language governing permissions and
+ : limitations under the License.
+:)
+
+(:~
+ : This module can be used for sending emails.
+ :
+ : The SMTP module contains only one public function that receives two parameters.
+ : The SMTP server access information passed as an <code>hostInfo</code> element
+ : and the email message representation as a <code>message</code> element.
+ : For a quick start see the examples associates with the <code>send(...)</code>
+ : function. For a complete specification read, the description and the
+ : documentation associated with this function.
+ :
+ : @author Sorin Nasoi, Daniel Thomas
+ : @see <a href="http://www.washington.edu/imap/";>c-client Library part of UW IMAP toolkit</a>
+ : @library <a href="http://www.washington.edu/imap/";>c-client Library part of UW IMAP toolkit</a>
+ : @project Zorba/Input Output/SMTP
+ :)
+module namespace smtp = "http://www.zorba-xquery.com/modules/email/smtp";;
+
+import schema namespace email = 'http://www.zorba-xquery.com/modules/email';
+
+declare namespace an = "http://zorba.io/annotations";;
+
+declare namespace ver = "http://zorba.io/options/versioning";;
+declare option ver:module-version "1.0";
+
+(:~
+ : This function sends an email message from the specified account.
+ :
+ : The <code>hostName</code> child element of <code>$host-info</code> must have the form:
+ : <code><b>remote_system_name</b> [":" <b>port</b>] [<b>flags</b>]</code>. This syntax is part of the
+ : <a href="http://www.washington.edu/imap/documentation/naming.txt.html"; target="_blank">Remote names</a>
+ : syntax defined in the UW IMAP toolkit. The <code><b>remote_system_name</b></code> and
+ : <code><b>flags</b></code> fragments are explained in the section <code>III</code> of this document.
+ :
+ : For example the hostName could look like:
+ : <ul>
+ : <li><code><hostName>smtp.gmail.com:587/tls/novalidate-cert<hostName></code></li>
+ : <li><code><hostName>[209.85.129.111]:587/tls/novalidate-cert<hostName></code></li>
+ : </ul>
+ :
+ : The <code>$host-info</code> parameter could then look like this:
+ : <pre class="ace-static" ace-mode="xquery"><![CDATA[
+ : <hostInfo>
+ : <hostName>smtp.gmail.com:587/tls/novalidate-cert</hostName>
+ : <userName>username</userName>
+ : <password>password</password>
+ : </hostInfo>
+ : ]]></pre>
+ :
+ : For a complete of the structure of an email message, see the imported email
+ : schema: <code>http://www.zorba-xquery.com/modules/email</code>
+ :
+ : All the data passed to this function does not need to be validated.
+ : The only requirement is that they have a valid format and are in the
+ : correct namespace according to the schema:
+ : <code>http://www.zorba-xquery.com/modules/email</code>.
+ :
+ : @param $host-info The SMTP host, user name, and password.
+ : @param $message The message to send as defined in the email XML schema.
+ : @return The function is declared as sequential and has side-effects. It returns the empty sequence.
+ : @error smtp:SMTP0001 The message format is invalid.
+ : @error smtp:SMTP0002 The message has no recipient.
+ : @error smtp:SMTP0003 The message could not be sent.
+ : @error smtp:SMTP9999 If any other error occurs.
+ : @error err:XQDY0027 If the values of the arguments are not not valid
+ : according to the email schema:
+ : <code>http://www.zorba-xquery.com/modules/email</code>
+ : @example examples/Queries/smtp/simple_text.xq
+ : @example examples/Queries/smtp/text_with_image.xq
+ : @example examples/Queries/smtp/html.xq
+ :)
+declare %an:sequential function smtp:send(
+ $host-info as element(email:hostInfo),
+ $message as element(email:message))
+ as empty-sequence()
+{
+ smtp:send-impl(validate{$host-info}, validate{$message})
+};
+
+declare %private %an:sequential function smtp:send-impl($host-info as element(email:hostInfo), $message as element(email:message)) as empty-sequence() external;
=== added directory 'src/com/zorba-xquery/www/modules/email/smtp.xq.src'
=== added file 'src/com/zorba-xquery/www/modules/email/smtp.xq.src/mime_handler.cpp'
--- src/com/zorba-xquery/www/modules/email/smtp.xq.src/mime_handler.cpp 1970-01-01 00:00:00 +0000
+++ src/com/zorba-xquery/www/modules/email/smtp.xq.src/mime_handler.cpp 2014-04-30 23:07:12 +0000
@@ -0,0 +1,647 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstdio>
+#include <sstream>
+#include <vector>
+
+#include <zorba/item_factory.h>
+#include <zorba/iterator.h>
+#include <zorba/store_consts.h>
+#include <zorba/user_exception.h>
+#include <zorba/util/base64_util.h>
+#include <zorba/xquery_functions.h>
+#include <zorba/zorba_string.h>
+
+#include "mime_handler.h"
+#include "email_exception.h"
+
+namespace zorba { namespace emailmodule {
+
+// helper function for retrieving the NodeName of an Item
+static void
+getNodeName(const Item aElement, zorba::String& aValue)
+{
+ Item lNodeName;
+ aElement.getNodeName(lNodeName);
+ aValue = lNodeName.getLocalName();
+}
+
+// helper function for retrieving the string value of a Text Node
+static void
+getTextValue(const Item aElement, zorba::String& aValue)
+{
+ Iterator_t lChildrenIt;
+ Item lChild;
+
+ aValue = String();
+ lChildrenIt = aElement.getChildren();
+ lChildrenIt->open();
+ while (lChildrenIt->next(lChild)) {
+ if (lChild.getNodeKind() == store::StoreConsts::textNode) {
+ aValue.append(lChild.getStringValue());
+ }
+ }
+
+ lChildrenIt->close();
+}
+
+/**
+ * Encodes a zorba String if necessary (if it contains non-ascii chars)
+ * and assigns it to the passed char-pointer-reference.
+ */
+void encodeStringForEMailHeader(const zorba::String& aString, char*& aCClientVal)
+{
+ // check if string contains non ascii chars
+ bool lContainsNonAscii = false;
+ for (
+ zorba::String::const_iterator lIter = aString.begin();
+ lIter != aString.end();
+ ++lIter)
+ {
+ unsigned int u = static_cast<unsigned int>(*lIter);
+ if (!(u == '\t' || u == '\n' || u == '\t' || (u >= 32 && u <= 127)))
+ {
+ lContainsNonAscii = true;
+ break;
+ }
+ }
+
+ if (lContainsNonAscii)
+ {
+ // if string contains non-ascii chars, we encode it with
+ // base64 encoding and generate a header value according to
+ // http://tools.ietf.org/html/rfc2047 (MIME encoded-word syntax).
+ zorba::String lEncodedValue;
+ zorba::base64::encode(aString, &lEncodedValue);
+ zorba::String lFullValue = zorba::String("=?UTF-8?B?")
+ + lEncodedValue
+ + zorba::String("?=");
+ aCClientVal = cpystr(lFullValue.c_str());
+ }
+ else
+ {
+ // if string contains ascii chars only, do don't encode anything
+ aCClientVal = cpystr(aString.c_str());
+ }
+}
+
+// helper function for retrieving the name and email address from an item
+static void
+getNameAndEmailAddress(
+ Item& aEmailItem,
+ String& aName,
+ String& aMailbox,
+ String& aHost)
+{
+ Iterator_t lChildren = aEmailItem.getChildren();
+ lChildren->open();
+ Item lChild;
+ // name might not exist -> empty string by default
+ aName = "";
+ while (lChildren->next(lChild)) {
+ if (lChild.getNodeKind() != store::StoreConsts::elementNode) {
+ continue;
+ }
+
+ String lNodeName;
+ getNodeName(lChild, lNodeName);
+ if (lNodeName == "name") {
+ aName = lChild.getStringValue();
+ } else {
+ String lEmail = lChild.getStringValue();
+ int lIndexOfAt = lEmail.find('@');
+ aMailbox = lEmail.substr(0, lIndexOfAt).c_str();
+ aHost = lEmail.substr(lIndexOfAt + 1, lEmail.length() - lIndexOfAt - 1).c_str();
+ }
+ }
+}
+
+mail_address*
+create_mail_address(String& aName, String& aMailbox, String& aHost)
+{
+ mail_address* address = mail_newaddr();
+ encodeStringForEMailHeader(aName, address->personal);
+ encodeStringForEMailHeader(aMailbox, address->mailbox);
+ encodeStringForEMailHeader(aHost, address->host);
+ return address;
+}
+
+
+CClientMimeHandler::~CClientMimeHandler()
+{
+}
+
+void
+CClientMimeHandler::begin(const Item& aMimeItem)
+{
+ Iterator_t lChildIter;
+
+ //initialize ENVELOPE
+ theEnvelope = mail_newenvelope ();
+
+ //initialize BODY
+ theBody = mail_newbody ();
+ mail_initbody(theBody);
+
+ //set theMessageItem
+ lChildIter = aMimeItem.getChildren();
+ lChildIter->open();
+
+ // read envelope and body elements but skip non-element nodes
+ while (lChildIter->next(theEnvelopeItem)) {
+ if (theEnvelopeItem.getNodeKind() == store::StoreConsts::elementNode) {
+ break;
+ }
+ }
+ while (lChildIter->next(theBodyItem)) {
+ if (theBodyItem.getNodeKind() == store::StoreConsts::elementNode) {
+ break;
+ }
+ }
+
+ lChildIter->close();
+}
+
+void
+CClientMimeHandler::end()
+{
+}
+
+void
+CClientMimeHandler::envelope()
+{
+ if (theEnvelopeItem.isNull()) {
+ throw EmailException("PARSE_ERROR", "The message could not be parsed.");
+ }
+
+ //set the date from the client.
+ //If this is not set it defaults to the date of the SMTP server.
+ char line[MAILTMPLEN];
+ rfc822_date (line);
+ theEnvelope->date = (unsigned char *) fs_get (1+strlen (line));
+ strcpy((char *)theEnvelope->date,line);
+
+
+ Iterator_t lChildIter;
+ zorba::Item lChild;
+ String lNodeName, lNodeValue;
+ String lName, lMailbox, lHost;
+
+ lChildIter = theEnvelopeItem.getChildren();
+ lChildIter->open();
+ while (lChildIter->next(lChild)) {
+ if (lChild.getNodeKind() != store::StoreConsts::elementNode) {
+ continue;
+ }
+
+ getNodeName(lChild, lNodeName);
+ getTextValue(lChild, lNodeValue);
+
+ if (lNodeName == "date") {
+ char lDate[MAILTMPLEN];
+ parseXmlDateTime(lNodeValue, lDate);
+ theEnvelope->date = (unsigned char *) fs_get (1+strlen (lDate));
+ strcpy ((char *)theEnvelope->date, lDate);
+ } else if (lNodeName == "from") {
+ getNameAndEmailAddress(lChild, lName, lMailbox, lHost);
+ theEnvelope->from = create_mail_address(lName, lMailbox, lHost);
+ } else if (lNodeName == "sender") {
+ getNameAndEmailAddress(lChild, lName, lMailbox, lHost);
+ theEnvelope->sender = create_mail_address(lName, lMailbox, lHost);
+ } else if (lNodeName == "replyto") {
+ getNameAndEmailAddress(lChild, lName, lMailbox, lHost);
+ theEnvelope->reply_to = create_mail_address(lName, lMailbox, lHost);
+ } else if (lNodeName == "subject") {
+ encodeStringForEMailHeader(lNodeValue, theEnvelope->subject);
+ } else if (lNodeName == "recipient") {
+ Iterator_t lRecipentChildren = lChild.getChildren();
+ lRecipentChildren->open();
+ Item lRecipentChild;
+ // read the recipient element but skip comments
+ while (lRecipentChildren->next(lRecipentChild)) {
+ if (lRecipentChild.getNodeKind() == store::StoreConsts::elementNode) {
+ break;
+ }
+ }
+ getNodeName(lRecipentChild, lNodeName);
+ lRecipentChildren->close();
+
+ if (lNodeName == "to") {
+ getNameAndEmailAddress(lRecipentChild, lName, lMailbox, lHost);
+ // there can be multiple to nodes, iterate to the next free one!
+ ADDRESS** lNext = &theEnvelope->to;
+ while (*lNext) {
+ lNext = &((*lNext)->next);
+ }
+ *lNext = create_mail_address(lName, lMailbox, lHost);
+ } else if(lNodeName == "cc") {
+ getNameAndEmailAddress(lRecipentChild, lName, lMailbox, lHost);
+ ADDRESS** lNext = &theEnvelope->cc;
+ while (*lNext) {
+ lNext = &((*lNext)->next);
+ }
+ *lNext = create_mail_address(lName, lMailbox, lHost);
+ } else if (lNodeName == "bcc") {
+ getNameAndEmailAddress(lRecipentChild, lName, lMailbox, lHost);
+ ADDRESS** lNext = &theEnvelope->bcc;
+ while (*lNext) {
+ lNext = &((*lNext)->next);
+ }
+ *lNext = create_mail_address(lName, lMailbox, lHost);
+ }
+ }
+ }
+ lChildIter->close();
+}
+
+void
+CClientMimeHandler::body()
+{
+ theBody->type = TYPEOTHER;
+
+ Iterator_t lChildIter;
+ Item lChild;
+ String lNodeName;
+
+ lChildIter = theBodyItem.getChildren();
+ lChildIter->open();
+ while (lChildIter->next(lChild)) {
+ if (lChild.getNodeKind() != store::StoreConsts::elementNode) {
+ continue;
+ }
+
+ getNodeName(lChild, lNodeName);
+
+ if (lNodeName == "content") {
+ parse_content(theBody, lChild);
+ }
+ else if (lNodeName == "multipart") {
+ parse_multipart(theBody, lChild);
+ }
+ }
+ lChildIter->close();
+}
+
+void
+CClientMimeHandler::set_text_body(BODY* aBody, String& aMessage)
+{
+ String lMessage;
+ // special case for encoding of base64 which needs a new line after 64 characters
+ if (aBody->encoding == ENCBASE64) {
+ std::stringstream lInStream;
+ std::stringstream lOutStream;
+ // for loop that counts to 64 and then makes a new line
+ lInStream << aMessage.c_str();
+ char next;
+ int counter = 0;
+ while (lInStream >> next) {
+ if (++counter == 64) {
+ lOutStream << "\r\n";
+ counter = 1;
+ }
+ lOutStream << next;
+ }
+ lMessage = lOutStream.str();
+ } else {
+ lMessage = aMessage;
+ }
+
+ char *text = (char *) fs_get (strlen(lMessage.c_str()));
+ text = cpystr (lMessage.c_str());
+ aBody->contents.text.size = strlen(text);
+ aBody->contents.text.data = (unsigned char *) text; //message body
+
+}
+
+PARAMETER*
+CClientMimeHandler::create_param(
+ String aAttribute,
+ String aValue,
+ PARAMETER* aPrevious)
+{
+ PARAMETER *lParam;
+ lParam = mail_newbody_parameter();
+ lParam->attribute = cpystr (aAttribute.c_str());
+ lParam->value = cpystr (aValue.c_str());
+
+ if (aPrevious) {
+ aPrevious->next = lParam;
+ }
+
+ return lParam;
+}
+
+void
+CClientMimeHandler::set_encoding(BODY* aBody, String& aEncoding)
+{
+ String lUpperEnc = fn::upper_case(aEncoding);
+
+ if (lUpperEnc == "ENC7BIT")
+ aBody->encoding = ENC7BIT;
+ else if (lUpperEnc == "ENC8BIT")
+ aBody->encoding = ENC8BIT;
+ else if (lUpperEnc == "ENCBINARY")
+ aBody->encoding = ENCBINARY;
+ else if (lUpperEnc == "ENCBASE64")
+ aBody->encoding = ENCBASE64;
+ else if (lUpperEnc == "ENCQUOTEDPRINTABLE")
+ aBody->encoding = ENCQUOTEDPRINTABLE;
+ else
+ aBody->encoding = ENCOTHER;
+}
+
+bool
+CClientMimeHandler::set_content_type_value(BODY* aBody, String& aValue)
+{
+ bool lRes = true;
+ int lPos = aValue.find('/');
+ String lLowerType = fn::lower_case(aValue.substr(0, lPos));
+
+ //set the BODY content type
+ if (lLowerType == "text")
+ aBody->type = TYPETEXT;
+ else if (lLowerType == "multipart")
+ aBody->type = TYPEMULTIPART;
+ else if (lLowerType == "message")
+ aBody->type = TYPEMESSAGE;
+ else if (lLowerType == "application")
+ aBody->type = TYPEAPPLICATION;
+ else if (lLowerType == "image")
+ aBody->type = TYPEIMAGE;
+ else if (lLowerType == "audio")
+ aBody->type = TYPEAUDIO;
+ else if (lLowerType == "video")
+ aBody->type = TYPEVIDEO;
+ else {
+ aBody->type = TYPEOTHER;
+ lRes = false;
+ }
+
+ //set the BODY content subtype
+ if (lRes) {
+ // the list of subtypes of each type is available at
+ // http://www.iana.org/assignments/media-types/
+ String lSubtype = aValue.substr(lPos + 1, aValue.length() - lPos);
+ aBody->subtype = cpystr(fn::upper_case(lSubtype).c_str());
+ }
+
+ return lRes;
+}
+
+void
+CClientMimeHandler::set_contentTypeCharsetCTF(
+ BODY* aBody,
+ const Item& aContentOrMultipartItem)
+{
+ Iterator_t lAttributes = aContentOrMultipartItem.getAttributes();
+ lAttributes->open();
+ Item lAttributeItem;
+ String lNodeName, lNodeValue;
+ while (lAttributes->next(lAttributeItem)) {
+ getNodeName(lAttributeItem, lNodeName);
+ lNodeValue = lAttributeItem.getStringValue();
+
+ if (lNodeName == "contentType") {
+ set_content_type_value(aBody, lNodeValue);
+ } else if (lNodeName == "charset") {
+ aBody->parameter = create_param("charset", fn::upper_case(lNodeValue), NIL);
+ } else if (lNodeName == "contentTransferEncoding") {
+ set_encoding(aBody, lNodeValue);
+ } else if (lNodeName == "contentDisposition") {
+ aBody->disposition.type = cpystr(fn::upper_case(lNodeValue).c_str());
+ } else if (lNodeName == "contentDisposition-filename") {
+ if (!aBody->disposition.parameter) {
+ aBody->disposition.parameter = create_param("filename", lNodeValue, NIL);
+ } else {
+ aBody->disposition.parameter->next = create_param("filename", lNodeValue, NIL);
+ }
+ } else if (lNodeName == "contentDisposition-modification-date") {
+ char lDate[MAILTMPLEN];
+ parseXmlDateTime(lNodeValue, lDate);
+ if (!aBody->disposition.parameter) {
+ aBody->disposition.parameter = create_param("modification-date", lDate);
+ } else {
+ aBody->disposition.parameter->next = create_param("modification-date", lDate);
+ }
+ }
+ }
+
+ lAttributes->close();
+}
+
+
+bool
+CClientMimeHandler::parse_content(BODY* aBody, const Item aItemContent)
+{
+ zorba::String lValue;
+
+ // set the contentType, charset and contentTransferEncoding (which are attributes of a content node)
+ set_contentTypeCharsetCTF(aBody, aItemContent);
+
+ lValue = aItemContent.getStringValue();
+ set_text_body(aBody, lValue);
+
+ return true;
+}
+
+bool
+CClientMimeHandler::parse_multipart(BODY* aBody, const Item aItemMultipart)
+{
+ Iterator_t lChildIter;
+ Item lChild;
+ String lNodeName, lNodeValue;
+ PART* lPartRoot = NIL;
+ PART* lPartPrev = NIL;
+
+ set_contentTypeCharsetCTF(aBody, aItemMultipart);
+
+ // a multipart node constists of several content or multipart nodes
+ lChildIter = aItemMultipart.getChildren();
+ lChildIter->open();
+ while (lChildIter->next(lChild)) {
+ if (lChild.getNodeKind() != store::StoreConsts::elementNode) {
+ continue;
+ }
+
+ // a simple content item
+ getNodeName(lChild, lNodeName);
+
+ if (lNodeName == "content") {
+ PART* lPart;
+ lPart = mail_newbody_part();
+ parse_content(&lPart->body, lChild);
+ if (lPartPrev) {
+ lPartPrev->next = lPart;
+ } else {
+ lPartRoot = lPart;
+ }
+ lPartPrev = lPart;
+ }
+ // a multipart item ... this calls for recursion
+ else if (lNodeName == "multipart") {
+ PART* lPart;
+ lPart = NIL;
+ lPart = mail_newbody_part();
+
+ parse_multipart(&lPart->body,lChild);
+
+ if (lPartPrev) {
+ lPartPrev->next = lPart;
+ } else {
+ lPartRoot = lPart;
+ }
+ lPartPrev = lPart;
+ }
+ }
+ lChildIter->close();
+
+ if (lPartRoot) {
+ aBody->nested.part = lPartRoot;
+ }
+
+ return true;
+}
+
+void
+CClientMimeHandler::parseXmlDateTime(String& aXmlDateTime, char* aCDateTime)
+{
+ // first we get year, month, day, hour, minute and seconds as zorba strings
+
+ int lTempIndex;
+ lTempIndex = aXmlDateTime.find('-');
+ String lYearString = aXmlDateTime.substr(0, lTempIndex);
+ aXmlDateTime = aXmlDateTime.substr(lTempIndex+1);
+
+ lTempIndex = aXmlDateTime.find('-');
+
+ String lMonthString = aXmlDateTime.substr(0, lTempIndex);
+ aXmlDateTime = aXmlDateTime.substr(lTempIndex+1);
+
+ lTempIndex = aXmlDateTime.find('T');
+
+ String lDayString = aXmlDateTime.substr(0, lTempIndex);
+ aXmlDateTime = aXmlDateTime.substr(lTempIndex+1);
+
+ lTempIndex = aXmlDateTime.find(':');
+
+ String lHourString = aXmlDateTime.substr(0, lTempIndex);
+ aXmlDateTime = aXmlDateTime.substr(lTempIndex+1);
+
+ lTempIndex = aXmlDateTime.find(':');
+
+ String lMinutesString = aXmlDateTime.substr(0, lTempIndex);
+ aXmlDateTime = aXmlDateTime.substr(lTempIndex+1);
+
+ // the next two digits specify the seconds
+ String lSecondsString = aXmlDateTime.substr(0, 2);
+
+
+ MESSAGECACHE * lDummyCache = mail_new_cache_elt (0);
+ unsigned int lTempDatePart;
+
+
+ // now, according to the specification of the dateTime xml type, we can have either: nothing, a Z (for UTC), -XXXX or +XXXX)
+ String lUTCString = aXmlDateTime.substr(2);
+
+ if (fn::starts_with(lUTCString,"+") || fn::starts_with(lUTCString,"-")) {
+ lTempIndex = lUTCString.find(':');
+ String lUTCHours = lUTCString.substr(1, lTempIndex-1);
+ String lUTCMinutes = lUTCString.substr(lTempIndex + 1);
+
+ std::stringstream lHoursConverter;
+ lHoursConverter << lUTCHours.c_str();
+ lHoursConverter >> lTempDatePart;
+ lDummyCache->zhours = lTempDatePart;
+
+ std::stringstream lMinutesConverter;
+ lMinutesConverter << lUTCMinutes.c_str();
+ lMinutesConverter >> lTempDatePart;
+ lDummyCache->zminutes = lTempDatePart;
+
+ if (fn::starts_with(lUTCString,"-")) {
+ lDummyCache->zoccident = 1;
+ }
+ }
+
+ // now we convert them and throw them into a dummy message cache
+ {
+ std::stringstream lConverter;
+ lConverter << lYearString.c_str();
+ lConverter >> lTempDatePart;
+ lTempDatePart -= 1970;
+ lDummyCache->year = lTempDatePart;
+ }
+
+ {
+ std::stringstream lConverter;
+ lConverter << lMonthString.c_str();
+ lConverter >> lTempDatePart;
+ lDummyCache->month = lTempDatePart;
+ }
+
+ {
+ std::stringstream lConverter;
+ lConverter << lDayString.c_str();
+ lConverter >> lTempDatePart;
+ lDummyCache->day = lTempDatePart;
+ }
+
+ {
+ std::stringstream lConverter;
+ lConverter << lHourString.c_str();
+ lConverter >> lTempDatePart;
+ lDummyCache->hours = lTempDatePart;
+ }
+
+ {
+ std::stringstream lConverter;
+ lConverter << lMinutesString.c_str();
+ lConverter >> lTempDatePart;
+ lDummyCache->minutes = lTempDatePart;
+ }
+
+ {
+ std::stringstream lConverter;
+ lConverter << lSecondsString.c_str();
+ lConverter >> lTempDatePart;
+ lDummyCache->seconds = lTempDatePart;
+ }
+
+ mail_cdate(aCDateTime, lDummyCache);
+
+ // like this, we have a string of the form: Sun Aug 8 08:40:40 2010 +0000\n
+ // what we actually would like is follwing: Fri, 10 Dec 2010 14:14:28 +0100 (CET)
+
+ std::stringstream lDate(aCDateTime);
+
+ std::string lDayAsWord;
+ std::string lMonthAsWord;
+ std::string lDay;
+ std::string lTime;
+ std::string lYear;
+ std::string lUTC;
+
+ lDate >> lDayAsWord >> lMonthAsWord >> lDay >> lTime >> lYear >> lUTC;
+
+ lDate.str(std::string());
+ lDate << lDayAsWord << ", " << lDay << " " << lMonthAsWord << " " << lYear << " " << lTime << " " << lUTC << " (UTF)";
+
+ strcpy(aCDateTime, lDate.str().c_str());
+}
+
+} //namespace emailmodule
+} //namespace zorba
=== added file 'src/com/zorba-xquery/www/modules/email/smtp.xq.src/mime_handler.h'
--- src/com/zorba-xquery/www/modules/email/smtp.xq.src/mime_handler.h 1970-01-01 00:00:00 +0000
+++ src/com/zorba-xquery/www/modules/email/smtp.xq.src/mime_handler.h 2014-04-30 23:07:12 +0000
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ZORBA_EMAILMODULE_MIMEHANDLER_H
+#define ZORBA_EMAILMODULE_MIMEHANDLER_H
+
+#include <istream>
+
+#include <zorba/item.h>
+
+#include "zorba/api_shared_types.h"
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include "c-client.h"
+
+namespace zorba { namespace emailmodule {
+
+class MimeHandler
+{
+ public:
+ virtual void begin(const Item& mimeItem) = 0;
+ virtual void envelope() = 0;
+ virtual void body() = 0;
+ virtual void end() = 0;
+};
+
+class CClientMimeHandler : public MimeHandler
+{
+ private:
+ // BODY and ENVELOPE structures are described in
+ // http://www.washington.edu/imap/documentation/internal.txt.html
+ BODY* theBody;
+ ENVELOPE* theEnvelope;
+ zorba::Item theEnvelopeItem;
+ zorba::Item theBodyItem;
+
+ // assign a certain message string to the given BODY
+ //TODO implement a streaming mechanism for large attachments
+ void
+ set_text_body(BODY* aBody,
+ String& aMessage);
+
+ // set the encoding to the given BODY
+ void
+ set_encoding(BODY* aBody,
+ zorba::String& aEncoding);
+
+ // set the content Type and content Subtype of the given BODY
+ bool
+ set_content_type_value(BODY* aBody,
+ zorba::String& aValue);
+
+ // helper function
+ PARAMETER *
+ create_param(
+ String aAttribute,
+ String aValue,
+ PARAMETER * aPrevious = NIL);
+
+ // parse non multipart message
+ bool
+ parse_content(BODY* aBody,
+ const Item aItemContent);
+
+ // parse multipart message
+ bool
+ parse_multipart(BODY* aBody,
+ const Item aItemMultipart);
+
+ // set contentType, charset and TranferEncoding
+ void
+ set_contentTypeCharsetCTF(BODY* aBody,
+ const Item& aContentOrMultipartItem);
+
+
+ // parse a xml dateTime string to something cclient will like
+ void
+ parseXmlDateTime(String& aXmlDateTime, char* aCDateTime);
+
+ public:
+ void begin(const Item& mimeItem);
+ void envelope();
+ void body();
+ void end();
+
+ BODY* getBody() { return theBody; };
+ ENVELOPE* getEnvelope() { return theEnvelope; };
+
+ // destroy theBody and theEnvelope
+ ~CClientMimeHandler();
+};
+
+} //namespace email
+} //namespace zorba
+
+#endif // ZORBA_EMAILMODULE_MIMEHANDLER_H
=== added file 'src/com/zorba-xquery/www/modules/email/smtp.xq.src/mime_parser.cpp'
--- src/com/zorba-xquery/www/modules/email/smtp.xq.src/mime_parser.cpp 1970-01-01 00:00:00 +0000
+++ src/com/zorba-xquery/www/modules/email/smtp.xq.src/mime_parser.cpp 2014-04-30 23:07:12 +0000
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mime_parser.h"
+
+namespace zorba { namespace emailmodule {
+
+void
+MimeParser::parse(const Item& aMimeItem, std::stringstream& aDiagnostics)
+{
+ theHandler->begin(aMimeItem);
+
+ theHandler->envelope();
+ theHandler->body();
+
+ theHandler->end();
+}
+
+} // namespace emailmodule
+} // namespace zorba
=== added file 'src/com/zorba-xquery/www/modules/email/smtp.xq.src/mime_parser.h'
--- src/com/zorba-xquery/www/modules/email/smtp.xq.src/mime_parser.h 1970-01-01 00:00:00 +0000
+++ src/com/zorba-xquery/www/modules/email/smtp.xq.src/mime_parser.h 2014-04-30 23:07:12 +0000
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ZORBA_EMAILMODULE_MIMEPARSER_H
+#define ZORBA_EMAILMODULE_MIMEPARSER_H
+
+#include "mime_handler.h"
+
+#include "zorba/api_shared_types.h"
+
+namespace zorba { namespace emailmodule {
+
+class MimeParser
+{
+ protected:
+ MimeHandler* theHandler;
+
+ public:
+ MimeParser(MimeHandler* aHandler) : theHandler(aHandler) {};
+
+ void
+ parse(const Item& aMimeItem, std::stringstream& aDiagnostics);
+};
+
+}//namespace emailmodule
+}//namespace zorba
+
+#endif // ZORBA_EMAILMODULE_MIMEPARSER_H
=== added file 'src/com/zorba-xquery/www/modules/email/smtp.xq.src/smtp.cpp'
--- src/com/zorba-xquery/www/modules/email/smtp.xq.src/smtp.cpp 1970-01-01 00:00:00 +0000
+++ src/com/zorba-xquery/www/modules/email/smtp.xq.src/smtp.cpp 2014-04-30 23:07:12 +0000
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+#include <sstream>
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <zorba/empty_sequence.h>
+#include <zorba/diagnostic_list.h>
+#include <zorba/user_exception.h>
+#include <zorba/singleton_item_sequence.h>
+
+#include "smtp_module.h"
+#include "imap_client.h"
+#include "email_exception.h"
+#include "mime_parser.h"
+#include "smtp.h"
+
+namespace zorba { namespace emailmodule {
+
+SendFunction::SendFunction(const SmtpModule* aModule)
+ : SmtpFunction(aModule)
+{
+}
+
+ItemSequence_t
+SendFunction::evaluate(
+ const ExternalFunction::Arguments_t& args,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const
+{
+ try {
+ // getting host, username and password
+ String lHostName, lUserName, lPassword;
+ getHostUserPassword(args, 0, lHostName, lUserName, lPassword);
+
+ std::stringstream lDiagnostics;
+ // getting message as item
+ Item messageItem;
+ Iterator_t arg1_iter = args[1]->getIterator();
+ arg1_iter->open();
+ arg1_iter->next(messageItem);
+ arg1_iter->close();
+
+ CClientMimeHandler lHandler;
+ MimeParser lParser(&lHandler);
+ lParser.parse(messageItem, lDiagnostics);
+
+ bool lHasRecipient = (lHandler.getEnvelope()->to ||
+ lHandler.getEnvelope()->cc ||
+ lHandler.getEnvelope()->bcc);
+
+ if (!lHasRecipient) {
+ throw EmailException("NO_RECIPIENT", "Message has no recipient.");
+ } else {
+ bool lRes = ImapClient::Instance().send(
+ lHostName.c_str(), lUserName.c_str(), lPassword.c_str(),
+ lHandler.getEnvelope(), lHandler.getBody(), lDiagnostics);
+ if (!lRes) {
+ std::stringstream lReport;
+ lReport
+ << "Message could not be sent. Reason: "
+ << lDiagnostics.str();
+ throw EmailException("NOT_SENT", lReport.str());
+ }
+ }
+ } catch (EmailException& e) {
+ raiseSmtpError(e);
+ }
+ return ItemSequence_t(NULL);
+}
+
+} // namespace emailmodule
+} // namespace zorba
+
+#ifdef WIN32
+# define DLL_EXPORT __declspec(dllexport)
+#else
+# define DLL_EXPORT __attribute__ ((visibility("default")))
+#endif
+
+extern "C" DLL_EXPORT zorba::ExternalModule* createModule() {
+ return new zorba::emailmodule::SmtpModule();
+}
=== added file 'src/com/zorba-xquery/www/modules/email/smtp.xq.src/smtp.h'
--- src/com/zorba-xquery/www/modules/email/smtp.xq.src/smtp.h 1970-01-01 00:00:00 +0000
+++ src/com/zorba-xquery/www/modules/email/smtp.xq.src/smtp.h 2014-04-30 23:07:12 +0000
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ZORBA_EMAILMODULE_SMTP_H
+#define ZORBA_EMAILMODULE_SMTP_H
+
+#include <zorba/zorba_string.h>
+
+#include "smtp_function.h"
+
+namespace zorba { namespace emailmodule {
+
+class SendFunction : public SmtpFunction
+{
+ public:
+ SendFunction(const SmtpModule* aModule);
+
+ virtual String
+ getLocalName() const { return "send-impl"; }
+
+ virtual ItemSequence_t
+ evaluate(
+ const ExternalFunction::Arguments_t& args,
+ const StaticContext* aSctxCtx,
+ const DynamicContext* aDynCtx) const;
+
+};
+
+} // namespace emailmodule
+} // namespace zorba
+
+#endif // ZORBA_EMAILMODULE_SMTP_H
=== added file 'src/com/zorba-xquery/www/modules/email/smtp.xq.src/smtp_function.cpp'
--- src/com/zorba-xquery/www/modules/email/smtp.xq.src/smtp_function.cpp 1970-01-01 00:00:00 +0000
+++ src/com/zorba-xquery/www/modules/email/smtp.xq.src/smtp_function.cpp 2014-04-30 23:07:12 +0000
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <zorba/zorba.h>
+#include <zorba/iterator.h>
+#include <zorba/item_sequence.h>
+#include <zorba/user_exception.h>
+#include <zorba/xquery_functions.h>
+#include <zorba/store_consts.h>
+
+#include "smtp_function.h"
+
+#include "smtp_module.h"
+
+namespace zorba { namespace emailmodule {
+
+SmtpFunction::SmtpFunction(const SmtpModule* aModule)
+ : theModule(aModule)
+{
+}
+
+SmtpFunction::~SmtpFunction()
+{
+}
+
+void
+SmtpFunction::raiseSmtpError(EmailException& e) const
+{
+ std::string lCode;
+ if (e.get_localname() == "PARSE_ERROR") {
+ lCode = "SMTP0001";
+ }
+ else if (e.get_localname() == "NO_RECIPIENT") {
+ lCode = "SMTP0002";
+ }
+ else if (e.get_localname() == "NOT_SENT") {
+ lCode = "SMTP0003";
+ }
+ else {
+ lCode = "SMTP9999";
+ }
+ raiseSmtpError(lCode, e.get_message());
+}
+
+void
+SmtpFunction::raiseSmtpError(
+ const std::string& aQName,
+ const std::string& aMessage) const
+{
+ std::stringstream lErrorMessage;
+ lErrorMessage << aMessage;
+ Item lQName = theModule->getItemFactory()->createQName(getURI(), "smtp", aQName);
+ throw USER_EXCEPTION(lQName, lErrorMessage.str());
+}
+
+String
+SmtpFunction::getURI() const
+{
+ return theModule->getURI();
+}
+
+void
+SmtpFunction::getHostUserPassword(
+ const ExternalFunction::Arguments_t& aArgs,
+ int aPos,
+ String& aHostName,
+ String& aUserName,
+ String& aPassword) const
+{
+ Item lNode;
+ Iterator_t lArgsIter = aArgs[aPos]->getIterator();
+ lArgsIter->open();
+ lArgsIter->next(lNode);
+ lArgsIter->close();
+
+ Item lChild;
+ Iterator_t lChildIter = lNode.getChildren();
+ lChildIter->open();
+
+ // now read the children but skipping non-element nodes
+ while (lChildIter->next(lChild)) {
+ if (lChild.getNodeKind() == store::StoreConsts::elementNode) {
+ break;
+ }
+ }
+ aHostName = lChild.getStringValue();
+ while (lChildIter->next(lChild)) {
+ if (lChild.getNodeKind() == store::StoreConsts::elementNode) {
+ break;
+ }
+ }
+ aUserName = lChild.getStringValue();
+ while (lChildIter->next(lChild)) {
+ if (lChild.getNodeKind() == store::StoreConsts::elementNode) {
+ break;
+ }
+ }
+ aPassword = lChild.getStringValue();
+ lChildIter->close();
+}
+
+} // namespace emailmodule
+} // namespace zorba
=== added file 'src/com/zorba-xquery/www/modules/email/smtp.xq.src/smtp_function.h'
--- src/com/zorba-xquery/www/modules/email/smtp.xq.src/smtp_function.h 1970-01-01 00:00:00 +0000
+++ src/com/zorba-xquery/www/modules/email/smtp.xq.src/smtp_function.h 2014-04-30 23:07:12 +0000
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ZORBA_EMAILMODULE_SMTPFUNCTION_H
+#define ZORBA_EMAILMODULE_SMTPFUNCTION_H
+
+#include <zorba/function.h>
+
+#include <email_exception.h>
+
+namespace zorba { namespace emailmodule {
+
+class SmtpModule;
+
+class SmtpFunction : public ContextualExternalFunction
+{
+ protected:
+ const SmtpModule* theModule;
+
+ public:
+ void
+ raiseSmtpError(
+ EmailException& e) const;
+
+ void
+ raiseSmtpError(
+ const std::string& qName,
+ const std::string& message) const;
+
+ virtual void
+ getHostUserPassword(
+ const ExternalFunction::Arguments_t& aArgs,
+ int aPos,
+ String& aHostName,
+ String& aUserName,
+ String& aPassword) const;
+
+ public:
+ SmtpFunction(const SmtpModule* aModule);
+ ~SmtpFunction();
+
+ virtual String
+ getURI() const;
+
+}; //class SmtpFunction
+
+} // namespace email
+} // namespace zorba
+
+#endif // ZORBA_EMAILMODULE_SMTPFUNCTION_H
=== added file 'src/com/zorba-xquery/www/modules/email/smtp.xq.src/smtp_module.cpp'
--- src/com/zorba-xquery/www/modules/email/smtp.xq.src/smtp_module.cpp 1970-01-01 00:00:00 +0000
+++ src/com/zorba-xquery/www/modules/email/smtp.xq.src/smtp_module.cpp 2014-04-30 23:07:12 +0000
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "smtp_module.h"
+
+#include "smtp.h"
+#include "smtp_function.h"
+
+namespace zorba { namespace emailmodule {
+
+ItemFactory* SmtpModule::theFactory = 0;
+
+SmtpModule::~SmtpModule()
+{
+ FuncMap_t::const_iterator lIter = theFunctions.begin();
+ for (; lIter != theFunctions.end(); ++lIter) {
+ delete lIter->second;
+ }
+
+ theFunctions.clear();
+}
+
+String
+SmtpModule::getURIString()
+{
+ return "http://www.zorba-xquery.com/modules/email/smtp";;
+}
+
+ExternalFunction*
+SmtpModule::getExternalFunction(const String& aLocalname)
+{
+ ExternalFunction*& lFunc = theFunctions[aLocalname];
+ if (!lFunc) {
+ if (aLocalname == "send-impl") {
+ lFunc = new SendFunction(this);
+ }
+ }
+ return lFunc;
+}
+
+void
+SmtpModule::destroy()
+{
+ if (!dynamic_cast<SmtpModule*>(this)) {
+ return;
+ }
+ delete this;
+}
+
+} // namespace email
+} // namespace zorba
=== added file 'src/com/zorba-xquery/www/modules/email/smtp.xq.src/smtp_module.h'
--- src/com/zorba-xquery/www/modules/email/smtp.xq.src/smtp_module.h 1970-01-01 00:00:00 +0000
+++ src/com/zorba-xquery/www/modules/email/smtp.xq.src/smtp_module.h 2014-04-30 23:07:12 +0000
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ZORBA_EMAILMODULE_SMTPMODULE_H
+#define ZORBA_EMAILMODULE_SMTPMODULE_H
+
+#include <map>
+
+#include <zorba/zorba.h>
+#include <zorba/external_module.h>
+
+namespace zorba { namespace emailmodule {
+
+class SmtpModule : public ExternalModule
+{
+ private:
+ static ItemFactory* theFactory;
+
+ protected:
+ class ltstr
+ {
+ public:
+ bool
+ operator()(const String& s1, const String& s2) const
+ {
+ return s1.compare(s2) < 0;
+ }
+ };
+
+ typedef std::map<String, ExternalFunction*, ltstr> FuncMap_t;
+ FuncMap_t theFunctions;
+
+ public:
+ virtual ~SmtpModule();
+
+ virtual String
+ getURI() const { return SmtpModule::getURIString(); }
+
+ static String
+ getURIString();
+
+ static ItemFactory*
+ getItemFactory()
+ {
+ if(!theFactory)
+ theFactory = Zorba::getInstance(0)->getItemFactory();
+ return theFactory;
+ }
+
+ virtual ExternalFunction*
+ getExternalFunction(const String& aLocalname);
+
+ virtual void
+ destroy();
+
+};
+
+} /* namespace emailmodule */
+} /* namespace zorba */
+
+#endif // ZORBA_EMAILMODULE_SMTPMODULE_H
References