lib: adds the mail submodule to curl
authorAlexis Laferrière <alexis.laf@xymus.net>
Mon, 29 Jul 2013 18:25:03 +0000 (14:25 -0400)
committerAlexis Laferrière <alexis.laf@xymus.net>
Mon, 29 Jul 2013 18:26:51 +0000 (14:26 -0400)
Signed-off-by: Alexis Laferrière <alexis.laf@xymus.net>

examples/curl_mail.nit [new file with mode: 0644]
lib/curl/curl.nit
lib/curl/mail.nit [new file with mode: 0644]
tests/sav/curl_mail.sav [new file with mode: 0644]

diff --git a/examples/curl_mail.nit b/examples/curl_mail.nit
new file mode 100644 (file)
index 0000000..4d60836
--- /dev/null
@@ -0,0 +1,46 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2013 Matthieu Lucas <lucasmatthieu@gmail.com>
+#
+# 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.
+
+# Mail sender sample using the Mail module
+module curl_mail
+
+import curl
+
+var mail = new Mail
+var err: nullable CURLCode
+
+# Networks
+err = mail.set_outgoing_server("smtps://smtp.example.org:465", "user@example.org", "mypassword")
+if err != null then print err.to_s
+mail.verbose = true
+
+# Headers
+var headers_body = new HashMap[String, String]
+headers_body["Content-Type:"] = "text/html; charset=\"UTF-8\""
+headers_body["Content-Transfer-Encoding:"] = "quoted-printable"
+mail.headers_body = headers_body
+mail.from = "Billy Bob"
+mail.to = ["user@example.org"]
+mail.cc = ["bob@example.org"]
+mail.bcc = null
+
+# Content
+mail.body = "<h1>Here you can write HTML stuff.</h1>"
+mail.subject = "Hello From My Nit Program"
+print "Mail Sent : {mail.send}"
+
+# GC
+mail.destroy
index 323e660..05dfe92 100644 (file)
@@ -18,6 +18,7 @@
 module curl
 
 import curl_c
+import mail
 
 # Top level of Curl
 class Curl
diff --git a/lib/curl/mail.nit b/lib/curl/mail.nit
new file mode 100644 (file)
index 0000000..c8e5c5c
--- /dev/null
@@ -0,0 +1,170 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2013 Matthieu Lucas <lucasmatthieu@gmail.com>
+#
+# 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.
+
+# Mail functionnalities based on Curl_c module.
+module mail
+
+import curl_c
+
+class Mail
+       super CCurlCallbacks
+
+       var headers: nullable HashMap[String, String] writable
+       var headers_body: nullable HashMap[String, String] writable
+       var from: nullable String writable
+       var to: nullable Array[String] writable
+       var cc: nullable Array[String] writable
+       var bcc: nullable Array[String] writable
+       var subject: nullable String writable
+       var body: nullable String writable
+       var verbose: Bool writable
+       private var curl: nullable CCurl
+       private var supported_outgoing_protocol: Array[String]
+
+       init
+       do
+               curl = new CCurl.easy_init
+               if not curl.is_init then curl = null
+
+               headers = null
+               headers_body = null
+               from = null
+               to = null
+               subject = ""
+               body = ""
+               verbose = false
+               supported_outgoing_protocol = once ["smtp", "smtps"]
+       end
+
+       # Helper method to add conventional space while building entire mail
+       private fun add_conventional_space(str: String):String do return "{str}\n" end
+
+       # Helper method to add pair values to mail content while building it (ex: "To:", "address@mail.com")
+       private fun add_pair_to_content(str: String, att: String, val: nullable String):String
+       do
+               if val != null then return "{str}{att}{val}\n"
+               return "{str}{att}\n"
+       end
+
+       # Check for host and protocol availability
+       private fun is_supported_outgoing_protocol(host: String):CURLCode
+       do
+               var host_reach = host.split_with("://")
+               if host_reach.length > 1 and supported_outgoing_protocol.has(host_reach[0]) then return once new CURLCode.ok
+               return once new CURLCode.unsupported_protocol
+       end
+
+       # Send mail with configured options (Headers, Headers_body To, Cc, Bcc, Subject, Body etc.)
+       fun send:Bool
+       do
+               # Check Curl initialisation
+               if self.curl == null then return false
+
+               var err: CURLCode
+               var content = ""
+
+               # Headers
+               if self.headers != null then
+                       for h_key, h_val in self.headers.as(not null) do
+                               content = add_pair_to_content(content, h_key, h_val)
+                       end
+               end
+
+               # Recipients
+               var g_rec = new Array[String]
+               if self.to != null and self.to.length > 0 then
+                       content = add_pair_to_content(content, "To:", self.to.join(","))
+                       g_rec.append(self.to.as(not null))
+               end
+               if self.cc != null and self.cc.length > 0 then
+                       content = add_pair_to_content(content, "Cc:", self.cc.join(","))
+                       g_rec.append(self.cc.as(not null))
+               end
+               if self.bcc != null and self.bcc.length > 0 then g_rec.append(self.bcc.as(not null))
+
+               if g_rec.length < 1 then return false
+               err = self.curl.easy_setopt(new CURLOption.mail_rcpt, g_rec.to_curlslist)
+               if not err.is_ok then return false
+
+               # From
+               if not self.from == null then
+                       content = add_pair_to_content(content, "From:", self.from)
+                       err = curl.easy_setopt(new CURLOption.mail_from, self.from.as(not null))
+                       if not err.is_ok then return false
+               end
+
+               # Subject
+               content = add_pair_to_content(content, "Subject:", self.subject)
+
+               # Headers body
+               if self.headers_body != null then
+                       for h_key, h_val in self.headers_body.as(not null) do
+                               content = add_pair_to_content(content, h_key, h_val)
+                       end
+               end
+
+               # Body
+               content = add_conventional_space(content)
+               content = add_pair_to_content(content, "", self.body)
+               content = add_conventional_space(content)
+               err = self.curl.register_callback(self, once new CURLCallbackType.read)
+               if not err.is_ok then return false
+               err = self.curl.register_read_datas_callback(self, content)
+               if not err.is_ok then return false
+
+               # Verbose
+               err = self.curl.easy_setopt(new CURLOption.verbose, self.verbose)
+               if not err.is_ok then return false
+
+               # Send
+               return self.curl.easy_perform.is_ok
+       end
+
+       # Configure server host and user credentials if needed.
+       fun set_outgoing_server(host: String, user: nullable String, pwd: nullable String):nullable CURLCode
+       do
+               # Check Curl initialisation
+               if self.curl == null then return new CURLCode.failed_init
+
+               var err: CURLCode
+
+               # Redirection
+               err = curl.easy_setopt(new CURLOption.follow_location, 1)
+               if not err.is_ok then return err
+
+               # Host & Protocol
+               err = is_supported_outgoing_protocol(host)
+               if not err.is_ok then return err
+               err = self.curl.easy_setopt(new CURLOption.url, host)
+               if not err.is_ok then return err
+
+               # Credentials
+               if not user == null and not pwd == null then
+                       err = self.curl.easy_setopt(new CURLOption.username, user)
+                       if not err.is_ok then return err
+                       err = self.curl.easy_setopt(new CURLOption.password, pwd)
+                       if not err.is_ok then return err
+               end
+
+               return null
+       end
+
+       # Releasing CURL instance
+       fun destroy
+       do
+               if self.curl != null then self.curl.easy_clean
+       end
+end
diff --git a/tests/sav/curl_mail.sav b/tests/sav/curl_mail.sav
new file mode 100644 (file)
index 0000000..2a9ad53
--- /dev/null
@@ -0,0 +1,5 @@
+* getaddrinfo(3) failed for smtp.example.org:465
+* Couldn't resolve host 'smtp.example.org'
+* Closing connection #0
+* Couldn't resolve host name
+Mail Sent : false