diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llmessage/llmail.cpp | |
parent | README.txt (diff) | |
download | meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2 meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz |
Second Life viewer sources 1.13.2.12
Diffstat (limited to '')
-rw-r--r-- | linden/indra/llmessage/llmail.cpp | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/linden/indra/llmessage/llmail.cpp b/linden/indra/llmessage/llmail.cpp new file mode 100644 index 0000000..e84d097 --- /dev/null +++ b/linden/indra/llmessage/llmail.cpp | |||
@@ -0,0 +1,311 @@ | |||
1 | /** | ||
2 | * @file llmail.cpp | ||
3 | * @brief smtp helper functions. | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #include "linden_common.h" | ||
29 | |||
30 | // APR on Windows needs full windows headers | ||
31 | #ifdef LL_WINDOWS | ||
32 | # undef WIN32_LEAN_AND_MEAN | ||
33 | # include <winsock2.h> | ||
34 | # include <windows.h> | ||
35 | #endif | ||
36 | |||
37 | #include <string> | ||
38 | #include <sstream> | ||
39 | #include <boost/regex.hpp> | ||
40 | |||
41 | #include "llmail.h" | ||
42 | |||
43 | #include "apr-1/apr_pools.h" | ||
44 | #include "apr-1/apr_network_io.h" | ||
45 | |||
46 | #include "llapr.h" | ||
47 | #include "llerror.h" | ||
48 | #include "llhost.h" | ||
49 | #include "net.h" | ||
50 | |||
51 | // | ||
52 | // constants | ||
53 | // | ||
54 | const size_t LL_MAX_KNOWN_GOOD_MAIL_SIZE = 4096; | ||
55 | |||
56 | static bool gMailEnabled = true; | ||
57 | static apr_pool_t* gMailPool; | ||
58 | static apr_sockaddr_t* gSockAddr; | ||
59 | static apr_socket_t* gMailSocket; | ||
60 | |||
61 | // According to RFC2822 | ||
62 | static const boost::regex valid_subject_chars("[\\x1-\\x9\\xb\\xc\\xe-\\x7f]+"); | ||
63 | bool connect_smtp(); | ||
64 | void disconnect_smtp(); | ||
65 | |||
66 | //#if LL_WINDOWS | ||
67 | //SOCKADDR_IN gMailDstAddr, gMailSrcAddr, gMailLclAddr; | ||
68 | //#else | ||
69 | //struct sockaddr_in gMailDstAddr, gMailSrcAddr, gMailLclAddr; | ||
70 | //#endif | ||
71 | |||
72 | // Define this for a super-spammy mail mode. | ||
73 | //#define LL_LOG_ENTIRE_MAIL_MESSAGE_ON_SEND 1 | ||
74 | |||
75 | bool connect_smtp() | ||
76 | { | ||
77 | // Prepare an soket to talk smtp | ||
78 | apr_status_t status; | ||
79 | status = apr_socket_create( | ||
80 | &gMailSocket, | ||
81 | gSockAddr->sa.sin.sin_family, | ||
82 | SOCK_STREAM, | ||
83 | APR_PROTO_TCP, | ||
84 | gMailPool); | ||
85 | if(ll_apr_warn_status(status)) return false; | ||
86 | status = apr_socket_connect(gMailSocket, gSockAddr); | ||
87 | if(ll_apr_warn_status(status)) | ||
88 | { | ||
89 | status = apr_socket_close(gMailSocket); | ||
90 | ll_apr_warn_status(status); | ||
91 | return false; | ||
92 | } | ||
93 | return true; | ||
94 | } | ||
95 | |||
96 | void disconnect_smtp() | ||
97 | { | ||
98 | if(gMailSocket) | ||
99 | { | ||
100 | apr_status_t status = apr_socket_close(gMailSocket); | ||
101 | ll_apr_warn_status(status); | ||
102 | gMailSocket = NULL; | ||
103 | } | ||
104 | } | ||
105 | |||
106 | // Returns TRUE on success. | ||
107 | // message should NOT be SMTP escaped. | ||
108 | BOOL send_mail(const char* from_name, const char* from_address, | ||
109 | const char* to_name, const char* to_address, | ||
110 | const char* subject, const char* message) | ||
111 | { | ||
112 | std::string header = build_smtp_transaction( | ||
113 | from_name, | ||
114 | from_address, | ||
115 | to_name, | ||
116 | to_address, | ||
117 | subject); | ||
118 | if(header.empty()) | ||
119 | { | ||
120 | return FALSE; | ||
121 | } | ||
122 | |||
123 | std::string message_str; | ||
124 | if(message) | ||
125 | { | ||
126 | message_str = message; | ||
127 | } | ||
128 | bool rv = send_mail(header, message_str, to_address, from_address); | ||
129 | if(rv) return TRUE; | ||
130 | return FALSE; | ||
131 | } | ||
132 | |||
133 | void init_mail(const std::string& hostname, apr_pool_t* pool) | ||
134 | { | ||
135 | gMailSocket = NULL; | ||
136 | if(hostname.empty() || !pool) | ||
137 | { | ||
138 | gMailPool = NULL; | ||
139 | gSockAddr = NULL; | ||
140 | } | ||
141 | else | ||
142 | { | ||
143 | gMailPool = pool; | ||
144 | |||
145 | // collect all the information into a socaddr sturcture. the | ||
146 | // documentation is a bit unclear, but I either have to | ||
147 | // specify APR_UNSPEC or not specify any flags. I am not sure | ||
148 | // which option is better. | ||
149 | apr_status_t status = apr_sockaddr_info_get( | ||
150 | &gSockAddr, | ||
151 | hostname.c_str(), | ||
152 | APR_UNSPEC, | ||
153 | 25, | ||
154 | APR_IPV4_ADDR_OK, | ||
155 | gMailPool); | ||
156 | ll_apr_warn_status(status); | ||
157 | } | ||
158 | } | ||
159 | |||
160 | void enable_mail(bool mail_enabled) | ||
161 | { | ||
162 | gMailEnabled = mail_enabled; | ||
163 | } | ||
164 | |||
165 | std::string build_smtp_transaction( | ||
166 | const char* from_name, | ||
167 | const char* from_address, | ||
168 | const char* to_name, | ||
169 | const char* to_address, | ||
170 | const char* subject) | ||
171 | { | ||
172 | if(!from_address || !to_address) | ||
173 | { | ||
174 | llinfos << "send_mail build_smtp_transaction reject: missing to and/or" | ||
175 | << " from address." << llendl; | ||
176 | return std::string(); | ||
177 | } | ||
178 | if(! boost::regex_match(subject, valid_subject_chars)) | ||
179 | { | ||
180 | llinfos << "send_mail build_smtp_transaction reject: bad subject header: " | ||
181 | << "to=<" << to_address | ||
182 | << ">, from=<" << from_address << ">" | ||
183 | << llendl; | ||
184 | return std::string(); | ||
185 | } | ||
186 | std::ostringstream from_fmt; | ||
187 | if(from_name && from_name[0]) | ||
188 | { | ||
189 | // "My Name" <myaddress@example.com> | ||
190 | from_fmt << "\"" << from_name << "\" <" << from_address << ">"; | ||
191 | } | ||
192 | else | ||
193 | { | ||
194 | // <myaddress@example.com> | ||
195 | from_fmt << "<" << from_address << ">"; | ||
196 | } | ||
197 | std::ostringstream to_fmt; | ||
198 | if(to_name && to_name[0]) | ||
199 | { | ||
200 | to_fmt << "\"" << to_name << "\" <" << to_address << ">"; | ||
201 | } | ||
202 | else | ||
203 | { | ||
204 | to_fmt << "<" << to_address << ">"; | ||
205 | } | ||
206 | std::ostringstream header; | ||
207 | header | ||
208 | << "HELO lindenlab.com\r\n" | ||
209 | << "MAIL FROM:<" << from_address << ">\r\n" | ||
210 | << "RCPT TO:<" << to_address << ">\r\n" | ||
211 | << "DATA\r\n" | ||
212 | << "From: " << from_fmt.str() << "\r\n" | ||
213 | << "To: " << to_fmt.str() << "\r\n" | ||
214 | << "Subject: " << subject << "\r\n" | ||
215 | << "\r\n"; | ||
216 | return header.str(); | ||
217 | } | ||
218 | |||
219 | bool send_mail( | ||
220 | const std::string& header, | ||
221 | const std::string& message, | ||
222 | const char* from_address, | ||
223 | const char* to_address) | ||
224 | { | ||
225 | if(!from_address || !to_address) | ||
226 | { | ||
227 | llinfos << "send_mail reject: missing to and/or from address." | ||
228 | << llendl; | ||
229 | return false; | ||
230 | } | ||
231 | |||
232 | // *FIX: this translation doesn't deal with a single period on a | ||
233 | // line by itself. | ||
234 | std::ostringstream rfc2822_msg; | ||
235 | for(U32 i = 0; i < message.size(); ++i) | ||
236 | { | ||
237 | switch(message[i]) | ||
238 | { | ||
239 | case '\0': | ||
240 | break; | ||
241 | case '\n': | ||
242 | // *NOTE: this is kinda busted if we're fed \r\n | ||
243 | rfc2822_msg << "\r\n"; | ||
244 | break; | ||
245 | default: | ||
246 | rfc2822_msg << message[i]; | ||
247 | break; | ||
248 | } | ||
249 | } | ||
250 | |||
251 | if(!gMailEnabled) | ||
252 | { | ||
253 | llinfos << "send_mail reject: mail system is disabled: to=<" | ||
254 | << to_address << ">, from=<" << from_address | ||
255 | << ">" << llendl; | ||
256 | // Any future interface to SMTP should return this as an | ||
257 | // error. --mark | ||
258 | return true; | ||
259 | } | ||
260 | if(!gSockAddr) | ||
261 | { | ||
262 | llwarns << "send_mail reject: mail system not initialized: to=<" | ||
263 | << to_address << ">, from=<" << from_address | ||
264 | << ">" << llendl; | ||
265 | return false; | ||
266 | } | ||
267 | |||
268 | if(!connect_smtp()) | ||
269 | { | ||
270 | llwarns << "send_mail reject: SMTP connect failure: to=<" | ||
271 | << to_address << ">, from=<" << from_address | ||
272 | << ">" << llendl; | ||
273 | return false; | ||
274 | } | ||
275 | |||
276 | std::ostringstream smtp_fmt; | ||
277 | smtp_fmt << header << rfc2822_msg.str() << "\r\n" << ".\r\n" << "QUIT\r\n"; | ||
278 | std::string smtp_transaction = smtp_fmt.str(); | ||
279 | size_t original_size = smtp_transaction.size(); | ||
280 | apr_size_t send_size = original_size; | ||
281 | apr_status_t status = apr_socket_send( | ||
282 | gMailSocket, | ||
283 | smtp_transaction.c_str(), | ||
284 | (apr_size_t*)&send_size); | ||
285 | disconnect_smtp(); | ||
286 | if(ll_apr_warn_status(status)) | ||
287 | { | ||
288 | llwarns << "send_mail socket failure: unable to write " | ||
289 | << "to=<" << to_address | ||
290 | << ">, from=<" << from_address << ">" | ||
291 | << ", bytes=" << original_size | ||
292 | << ", sent=" << send_size << llendl; | ||
293 | return false; | ||
294 | } | ||
295 | if(send_size >= LL_MAX_KNOWN_GOOD_MAIL_SIZE) | ||
296 | { | ||
297 | llwarns << "send_mail message has been shown to fail in testing " | ||
298 | << "when sending messages larger than " << LL_MAX_KNOWN_GOOD_MAIL_SIZE | ||
299 | << " bytes. The next log about success is potentially a lie." << llendl; | ||
300 | } | ||
301 | llinfos << "send_mail success: " | ||
302 | << "to=<" << to_address | ||
303 | << ">, from=<" << from_address << ">" | ||
304 | << ", bytes=" << original_size | ||
305 | << ", sent=" << send_size << llendl; | ||
306 | |||
307 | #if LL_LOG_ENTIRE_MAIL_MESSAGE_ON_SEND | ||
308 | llinfos << rfc2822_msg.str() << llendl; | ||
309 | #endif | ||
310 | return true; | ||
311 | } | ||