lib: fix precision of test_curl
[nit.git] / lib / curl / mail.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2013 Matthieu Lucas <lucasmatthieu@gmail.com>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Mail functionnalities based on Curl_c module.
18 module mail
19
20 import curl_c
21
22 class Mail
23 super CCurlCallbacks
24
25 var headers: nullable HashMap[String, String] writable
26 var headers_body: nullable HashMap[String, String] writable
27 var from: nullable String writable
28 var to: nullable Array[String] writable
29 var cc: nullable Array[String] writable
30 var bcc: nullable Array[String] writable
31 var subject: nullable String writable
32 var body: nullable String writable
33 var verbose: Bool writable
34 private var curl: nullable CCurl
35 private var supported_outgoing_protocol: Array[String]
36
37 init
38 do
39 curl = new CCurl.easy_init
40 if not curl.is_init then curl = null
41
42 headers = null
43 headers_body = null
44 from = null
45 to = null
46 subject = ""
47 body = ""
48 verbose = false
49 supported_outgoing_protocol = once ["smtp", "smtps"]
50 end
51
52 # Helper method to add conventional space while building entire mail
53 private fun add_conventional_space(str: String):String do return "{str}\n" end
54
55 # Helper method to add pair values to mail content while building it (ex: "To:", "address@mail.com")
56 private fun add_pair_to_content(str: String, att: String, val: nullable String):String
57 do
58 if val != null then return "{str}{att}{val}\n"
59 return "{str}{att}\n"
60 end
61
62 # Check for host and protocol availability
63 private fun is_supported_outgoing_protocol(host: String):CURLCode
64 do
65 var host_reach = host.split_with("://")
66 if host_reach.length > 1 and supported_outgoing_protocol.has(host_reach[0]) then return once new CURLCode.ok
67 return once new CURLCode.unsupported_protocol
68 end
69
70 # Send mail with configured options (Headers, Headers_body To, Cc, Bcc, Subject, Body etc.)
71 fun send:Bool
72 do
73 # Check Curl initialisation
74 if self.curl == null then return false
75
76 var err: CURLCode
77 var content = ""
78
79 # Headers
80 if self.headers != null then
81 for h_key, h_val in self.headers.as(not null) do
82 content = add_pair_to_content(content, h_key, h_val)
83 end
84 end
85
86 # Recipients
87 var g_rec = new Array[String]
88 if self.to != null and self.to.length > 0 then
89 content = add_pair_to_content(content, "To:", self.to.join(","))
90 g_rec.append(self.to.as(not null))
91 end
92 if self.cc != null and self.cc.length > 0 then
93 content = add_pair_to_content(content, "Cc:", self.cc.join(","))
94 g_rec.append(self.cc.as(not null))
95 end
96 if self.bcc != null and self.bcc.length > 0 then g_rec.append(self.bcc.as(not null))
97
98 if g_rec.length < 1 then return false
99 err = self.curl.easy_setopt(new CURLOption.mail_rcpt, g_rec.to_curlslist)
100 if not err.is_ok then return false
101
102 # From
103 if not self.from == null then
104 content = add_pair_to_content(content, "From:", self.from)
105 err = curl.easy_setopt(new CURLOption.mail_from, self.from.as(not null))
106 if not err.is_ok then return false
107 end
108
109 # Subject
110 content = add_pair_to_content(content, "Subject:", self.subject)
111
112 # Headers body
113 if self.headers_body != null then
114 for h_key, h_val in self.headers_body.as(not null) do
115 content = add_pair_to_content(content, h_key, h_val)
116 end
117 end
118
119 # Body
120 content = add_conventional_space(content)
121 content = add_pair_to_content(content, "", self.body)
122 content = add_conventional_space(content)
123 err = self.curl.register_callback(self, once new CURLCallbackType.read)
124 if not err.is_ok then return false
125 err = self.curl.register_read_datas_callback(self, content)
126 if not err.is_ok then return false
127
128 # Verbose
129 err = self.curl.easy_setopt(new CURLOption.verbose, self.verbose)
130 if not err.is_ok then return false
131
132 # Send
133 return self.curl.easy_perform.is_ok
134 end
135
136 # Configure server host and user credentials if needed.
137 fun set_outgoing_server(host: String, user: nullable String, pwd: nullable String):nullable CURLCode
138 do
139 # Check Curl initialisation
140 if self.curl == null then return new CURLCode.failed_init
141
142 var err: CURLCode
143
144 # Redirection
145 err = curl.easy_setopt(new CURLOption.follow_location, 1)
146 if not err.is_ok then return err
147
148 # Host & Protocol
149 err = is_supported_outgoing_protocol(host)
150 if not err.is_ok then return err
151 err = self.curl.easy_setopt(new CURLOption.url, host)
152 if not err.is_ok then return err
153
154 # Credentials
155 if not user == null and not pwd == null then
156 err = self.curl.easy_setopt(new CURLOption.username, user)
157 if not err.is_ok then return err
158 err = self.curl.easy_setopt(new CURLOption.password, pwd)
159 if not err.is_ok then return err
160 end
161
162 return null
163 end
164
165 # Releasing CURL instance
166 fun destroy
167 do
168 if self.curl != null then self.curl.easy_clean
169 end
170 end