aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llmessage/llmail.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llmessage/llmail.cpp
parentREADME.txt (diff)
downloadmeta-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.cpp311
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//
54const size_t LL_MAX_KNOWN_GOOD_MAIL_SIZE = 4096;
55
56static bool gMailEnabled = true;
57static apr_pool_t* gMailPool;
58static apr_sockaddr_t* gSockAddr;
59static apr_socket_t* gMailSocket;
60
61// According to RFC2822
62static const boost::regex valid_subject_chars("[\\x1-\\x9\\xb\\xc\\xe-\\x7f]+");
63bool connect_smtp();
64void 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
75bool 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
96void 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.
108BOOL 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
133void 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
160void enable_mail(bool mail_enabled)
161{
162 gMailEnabled = mail_enabled;
163}
164
165std::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
219bool 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}