EmailModule.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSimulator Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using System;
  28. using System.Collections.Generic;
  29. using System.Net.Security;
  30. using System.Reflection;
  31. using System.Security.Cryptography.X509Certificates;
  32. using log4net;
  33. using MailKit;
  34. using MailKit.Net.Smtp;
  35. using MimeKit;
  36. using Nini.Config;
  37. using OpenMetaverse;
  38. using OpenSim.Framework;
  39. using OpenSim.Region.Framework.Interfaces;
  40. using OpenSim.Region.Framework.Scenes;
  41. using Mono.Addins;
  42. namespace OpenSim.Region.CoreModules.Scripting.EmailModules
  43. {
  44. [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "EmailModule")]
  45. public class EmailModule : ISharedRegionModule, IEmailModule
  46. {
  47. public class throttleControlInfo
  48. {
  49. public double lastTime;
  50. public double count;
  51. }
  52. //
  53. // Log
  54. //
  55. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  56. //
  57. // Module vars
  58. //
  59. private string m_HostName = string.Empty;
  60. private bool SMTP_SERVER_TLS = false;
  61. private string SMTP_SERVER_HOSTNAME = null;
  62. private int SMTP_SERVER_PORT = 25;
  63. private MailboxAddress SMTP_MAIL_FROM = null;
  64. private string SMTP_SERVER_LOGIN = null;
  65. private string SMTP_SERVER_PASSWORD = null;
  66. private bool m_enableEmailToExternalObjects = true;
  67. private bool m_enableEmailToSMTP = true;
  68. private ParserOptions m_mailParseOptions;
  69. private int m_MaxQueueSize = 50; // maximum size of an object mail queue
  70. private Dictionary<UUID, List<Email>> m_MailQueues = new Dictionary<UUID, List<Email>>();
  71. private Dictionary<UUID, double> m_LastGetEmailCall = new Dictionary<UUID, double>();
  72. private Dictionary<UUID, throttleControlInfo> m_ownerThrottles = new Dictionary<UUID, throttleControlInfo>();
  73. private Dictionary<string, throttleControlInfo> m_primAddressThrottles = new Dictionary<string, throttleControlInfo>();
  74. private Dictionary<string, throttleControlInfo> m_SMPTAddressThrottles = new Dictionary<string, throttleControlInfo>();
  75. private double m_QueueTimeout = 30 * 60; // 15min;
  76. private double m_nextQueuesExpire;
  77. private double m_nextOwnerThrottlesExpire;
  78. private double m_nextPrimAddressThrottlesExpire;
  79. private double m_nextSMTPAddressThrottlesExpire;
  80. private string m_InterObjectHostname = "lsl.opensim.local";
  81. private int m_SMTP_MailsPerDay = 100;
  82. private double m_SMTP_MailsRate = 100.0 / 86400.0;
  83. private double m_SMTPLastTime;
  84. private double m_SMTPCount;
  85. private int m_MailsToPrimAddressPerHour = 50;
  86. private double m_MailsToPrimAddressRate = 50.0 / 3600.0;
  87. private int m_MailsToSMTPAddressPerHour = 10;
  88. private double m_MailsToSMTPAddressRate = 20.0 / 3600.0;
  89. private int m_MailsFromOwnerPerHour = 500;
  90. private double m_MailsFromOwnerRate = 500.0 / 3600.0;
  91. private int m_MaxEmailSize = 4096; // largest email allowed by default, as per lsl docs.
  92. private static SslPolicyErrors m_SMTP_SslPolicyErrorsMask;
  93. private bool m_checkSpecName;
  94. private object m_queuesLock = new object();
  95. // Scenes by Region Handle
  96. private Dictionary<ulong, Scene> m_Scenes = new Dictionary<ulong, Scene>();
  97. private bool m_Enabled = false;
  98. #region ISharedRegionModule
  99. public void Initialise(IConfigSource config)
  100. {
  101. IConfig startupConfig = config.Configs["Startup"];
  102. if(startupConfig == null)
  103. return;
  104. if(startupConfig.GetString("emailmodule", "DefaultEmailModule") != "DefaultEmailModule")
  105. return;
  106. //Load SMTP SERVER config
  107. try
  108. {
  109. IConfig SMTPConfig = config.Configs["SMTP"];
  110. if (SMTPConfig == null)
  111. return;
  112. if(!SMTPConfig.GetBoolean("enabled", false))
  113. return;
  114. m_enableEmailToExternalObjects = SMTPConfig.GetBoolean("enableEmailToExternalObjects", m_enableEmailToExternalObjects);
  115. m_enableEmailToSMTP = SMTPConfig.GetBoolean("enableEmailToSMTP", m_enableEmailToSMTP);
  116. m_MailsToPrimAddressPerHour = SMTPConfig.GetInt("MailsToPrimAddressPerHour", m_MailsToPrimAddressPerHour);
  117. m_MailsToPrimAddressRate = m_MailsToPrimAddressPerHour / 3600.0;
  118. m_MailsFromOwnerPerHour = SMTPConfig.GetInt("MailsFromOwnerPerHour", m_MailsFromOwnerPerHour);
  119. m_MailsFromOwnerRate = m_MailsFromOwnerPerHour / 3600.0;
  120. m_mailParseOptions = new ParserOptions()
  121. {
  122. AllowAddressesWithoutDomain = false,
  123. };
  124. m_InterObjectHostname = SMTPConfig.GetString("internal_object_host", m_InterObjectHostname);
  125. m_checkSpecName = !m_InterObjectHostname.Equals("lsl.secondlife.com");
  126. if (m_enableEmailToSMTP)
  127. {
  128. m_SMTP_MailsPerDay = SMTPConfig.GetInt("SMTP_MailsPerDay", m_SMTP_MailsPerDay);
  129. m_SMTP_MailsRate = m_SMTP_MailsPerDay / 86400.0;
  130. m_MailsToSMTPAddressPerHour = SMTPConfig.GetInt("MailsToSMTPAddressPerHour", m_MailsToPrimAddressPerHour);
  131. m_MailsToSMTPAddressRate = m_MailsToPrimAddressPerHour / 3600.0;
  132. SMTP_SERVER_HOSTNAME = SMTPConfig.GetString("SMTP_SERVER_HOSTNAME", SMTP_SERVER_HOSTNAME);
  133. OSHHTPHost hosttmp = new OSHHTPHost(SMTP_SERVER_HOSTNAME, true);
  134. if(!hosttmp.IsResolvedHost)
  135. {
  136. m_log.ErrorFormat("[EMAIL]: could not resolve SMTP_SERVER_HOSTNAME {0}", SMTP_SERVER_HOSTNAME);
  137. return;
  138. }
  139. SMTP_SERVER_PORT = SMTPConfig.GetInt("SMTP_SERVER_PORT", SMTP_SERVER_PORT);
  140. SMTP_SERVER_TLS = SMTPConfig.GetBoolean("SMTP_SERVER_TLS", SMTP_SERVER_TLS);
  141. string smtpfrom = SMTPConfig.GetString("SMTP_SERVER_FROM", string.Empty);
  142. m_HostName = SMTPConfig.GetString("host_domain_header_from", m_HostName);
  143. if (!string.IsNullOrEmpty(smtpfrom) && !MailboxAddress.TryParse(m_mailParseOptions, smtpfrom, out SMTP_MAIL_FROM))
  144. {
  145. m_log.ErrorFormat("[EMAIL]: Invalid SMTP_SERVER_FROM {0}", smtpfrom);
  146. return;
  147. }
  148. SMTP_SERVER_LOGIN = SMTPConfig.GetString("SMTP_SERVER_LOGIN", SMTP_SERVER_LOGIN);
  149. SMTP_SERVER_PASSWORD = SMTPConfig.GetString("SMTP_SERVER_PASSWORD", SMTP_SERVER_PASSWORD);
  150. bool VerifyCertChain = SMTPConfig.GetBoolean("SMTP_VerifyCertChain", true);
  151. bool VerifyCertNames = SMTPConfig.GetBoolean("SMTP_VerifyCertNames", true);
  152. m_SMTP_SslPolicyErrorsMask = VerifyCertChain ? 0 : SslPolicyErrors.RemoteCertificateChainErrors;
  153. if (!VerifyCertNames)
  154. m_SMTP_SslPolicyErrorsMask |= SslPolicyErrors.RemoteCertificateNameMismatch;
  155. m_SMTP_SslPolicyErrorsMask = ~m_SMTP_SslPolicyErrorsMask;
  156. }
  157. else
  158. {
  159. m_SMTP_SslPolicyErrorsMask = ~SslPolicyErrors.None;
  160. m_log.Warn("[EMAIL]: SMTP disabled, set enableEmailSMTP to enable");
  161. }
  162. m_MaxEmailSize = SMTPConfig.GetInt("email_max_size", m_MaxEmailSize);
  163. if(m_MaxEmailSize < 256 || m_MaxEmailSize > 1000000)
  164. {
  165. m_log.Warn("[EMAIL]: email_max_size out of range [256, 1000000], Changed to default 4096");
  166. m_MaxEmailSize = 4096;
  167. }
  168. }
  169. catch (Exception e)
  170. {
  171. m_log.Error("[EMAIL]: DefaultEmailModule not configured: " + e.Message);
  172. return;
  173. }
  174. double now = Util.GetTimeStamp();
  175. m_nextQueuesExpire = now + m_QueueTimeout;
  176. m_nextOwnerThrottlesExpire = now + 3600;
  177. m_nextPrimAddressThrottlesExpire = now + 3600;
  178. m_nextSMTPAddressThrottlesExpire = now + 3600;
  179. m_SMTPLastTime = now;
  180. m_SMTPCount = m_SMTP_MailsPerDay;
  181. m_Enabled = true;
  182. }
  183. public void AddRegion(Scene scene)
  184. {
  185. if (!m_Enabled)
  186. return;
  187. // It's a go!
  188. lock (m_Scenes)
  189. {
  190. // Claim the interface slot
  191. scene.RegisterModuleInterface<IEmailModule>(this);
  192. // Add to scene list
  193. m_Scenes[scene.RegionInfo.RegionHandle] = scene;
  194. }
  195. m_log.Info("[EMAIL]: Activated DefaultEmailModule");
  196. }
  197. public void RemoveRegion(Scene scene)
  198. {
  199. }
  200. public void PostInitialise()
  201. {
  202. }
  203. public void Close()
  204. {
  205. }
  206. public string Name
  207. {
  208. get { return "DefaultEmailModule"; }
  209. }
  210. public Type ReplaceableInterface
  211. {
  212. get { return null; }
  213. }
  214. public void RegionLoaded(Scene scene)
  215. {
  216. }
  217. #endregion
  218. public void AddPartMailBox(UUID objectID)
  219. {
  220. if (m_Enabled)
  221. {
  222. lock (m_queuesLock)
  223. {
  224. if (!m_MailQueues.TryGetValue(objectID, out List<Email> elist))
  225. {
  226. m_MailQueues[objectID] = null;
  227. //TODO external global
  228. }
  229. }
  230. }
  231. }
  232. public void RemovePartMailBox(UUID objectID)
  233. {
  234. if (m_Enabled)
  235. {
  236. lock (m_queuesLock)
  237. {
  238. m_LastGetEmailCall.Remove(objectID);
  239. if (m_MailQueues.Remove(objectID))
  240. {
  241. //TODO external global
  242. }
  243. }
  244. }
  245. }
  246. public void InsertEmail(UUID to, Email email)
  247. {
  248. lock (m_queuesLock)
  249. {
  250. if (m_MailQueues.TryGetValue(to, out List<Email> elist))
  251. {
  252. if(elist == null)
  253. {
  254. elist = new List<Email>();
  255. elist.Add(email);
  256. m_MailQueues[to] = elist;
  257. }
  258. else
  259. {
  260. if (elist.Count >= m_MaxQueueSize)
  261. return;
  262. lock (elist)
  263. elist.Add(email);
  264. }
  265. m_LastGetEmailCall[to] = Util.GetTimeStamp() + m_QueueTimeout;
  266. }
  267. }
  268. }
  269. private bool IsLocal(UUID objectID)
  270. {
  271. lock (m_Scenes)
  272. {
  273. foreach (Scene s in m_Scenes.Values)
  274. {
  275. if (s.GetSceneObjectPart(objectID) != null)
  276. return true;
  277. }
  278. }
  279. return false;
  280. }
  281. private SceneObjectPart findPrim(UUID objectID, out string ObjectRegionName)
  282. {
  283. lock (m_Scenes)
  284. {
  285. foreach (Scene s in m_Scenes.Values)
  286. {
  287. SceneObjectPart part = s.GetSceneObjectPart(objectID);
  288. if (part != null)
  289. {
  290. RegionInfo sri = s.RegionInfo;
  291. ObjectRegionName = sri.RegionName;
  292. ObjectRegionName = ObjectRegionName + " (" + sri.WorldLocX + ", " + sri.WorldLocY + ")";
  293. return part;
  294. }
  295. }
  296. }
  297. ObjectRegionName = string.Empty;
  298. return null;
  299. }
  300. private bool resolveNamePositionRegionName(UUID objectID, out string ObjectName, out string ObjectAbsolutePosition, out string ObjectRegionName)
  301. {
  302. SceneObjectPart part = findPrim(objectID, out ObjectRegionName);
  303. if (part != null)
  304. {
  305. Vector3 pos = part.AbsolutePosition;
  306. ObjectAbsolutePosition = "(" + (int)pos.X + ", " + (int)pos.Y + ", " + (int)pos.Z + ")";
  307. ObjectName = part.Name;
  308. return true;
  309. }
  310. ObjectName = ObjectAbsolutePosition = ObjectRegionName = string.Empty;
  311. return false;
  312. }
  313. public static bool smptValidateServerCertificate(object sender, X509Certificate certificate,
  314. X509Chain chain, SslPolicyErrors sslPolicyErrors)
  315. {
  316. return (sslPolicyErrors & m_SMTP_SslPolicyErrorsMask) == SslPolicyErrors.None;
  317. }
  318. /// <summary>
  319. /// SendMail function utilized by llEMail
  320. /// </summary>
  321. /// <param name="objectID"></param>
  322. /// <param name="address"></param>
  323. /// <param name="subject"></param>
  324. /// <param name="body"></param>
  325. public void SendEmail(UUID objectID, UUID ownerID, string address, string subject, string body)
  326. {
  327. //Check if address is empty or too large
  328. if(string.IsNullOrEmpty(address))
  329. return;
  330. address = address.Trim();
  331. if (address.Length == 0 || address.Length > 320)
  332. return;
  333. double now = Util.GetTimeStamp();
  334. throttleControlInfo tci;
  335. lock (m_ownerThrottles)
  336. {
  337. if (m_ownerThrottles.TryGetValue(ownerID, out tci))
  338. {
  339. tci.count += (now - tci.lastTime) * m_MailsFromOwnerRate;
  340. tci.lastTime = now;
  341. if (tci.count > m_MailsFromOwnerPerHour)
  342. tci.count = m_MailsFromOwnerPerHour;
  343. else if (tci.count <= 0)
  344. return;
  345. --tci.count;
  346. }
  347. else
  348. {
  349. tci = new throttleControlInfo
  350. {
  351. lastTime = now,
  352. count = m_MailsFromOwnerPerHour
  353. };
  354. m_ownerThrottles[ownerID] = tci;
  355. }
  356. }
  357. string addressLower = address.ToLower();
  358. if (!MailboxAddress.TryParse(address, out MailboxAddress mailTo))
  359. {
  360. m_log.ErrorFormat("[EMAIL]: invalid TO email address {0}",address);
  361. return;
  362. }
  363. if ((subject.Length + body.Length) > m_MaxEmailSize)
  364. {
  365. m_log.Error("[EMAIL]: subject + body larger than limit of " + m_MaxEmailSize + " bytes");
  366. return;
  367. }
  368. if (!resolveNamePositionRegionName(objectID, out string LastObjectName, out string LastObjectPosition, out string LastObjectRegionName))
  369. return;
  370. string objectIDstr = objectID.ToString();
  371. if (!address.EndsWith(m_InterObjectHostname, StringComparison.InvariantCultureIgnoreCase) &&
  372. !(m_checkSpecName && address.EndsWith("lsl.secondlife.com", StringComparison.InvariantCultureIgnoreCase)))
  373. {
  374. if(!m_enableEmailToSMTP)
  375. return; //smtp disabled
  376. m_SMTPCount += (m_SMTPLastTime - now) * m_SMTP_MailsRate;
  377. m_SMTPLastTime = now;
  378. if (m_SMTPCount > m_SMTP_MailsPerDay)
  379. m_SMTPCount = m_SMTP_MailsPerDay;
  380. else if (m_SMTPCount <= 0)
  381. return;
  382. --m_SMTPCount;
  383. lock (m_SMPTAddressThrottles)
  384. {
  385. if (m_SMPTAddressThrottles.TryGetValue(addressLower, out tci))
  386. {
  387. tci.count += (now - tci.lastTime) * m_MailsToSMTPAddressRate;
  388. tci.lastTime = now;
  389. if (tci.count > m_MailsToSMTPAddressPerHour)
  390. tci.count = m_MailsToSMTPAddressPerHour;
  391. else if (tci.count <= 0)
  392. return;
  393. --tci.count;
  394. }
  395. else
  396. {
  397. tci = new throttleControlInfo
  398. {
  399. lastTime = now,
  400. count = m_MailsToSMTPAddressPerHour
  401. };
  402. m_SMPTAddressThrottles[addressLower] = tci;
  403. }
  404. }
  405. // regular email, send it out
  406. try
  407. {
  408. //Creation EmailMessage
  409. MimeMessage mmsg = new MimeMessage();
  410. if(SMTP_MAIL_FROM != null)
  411. {
  412. mmsg.From.Add(SMTP_MAIL_FROM);
  413. mmsg.Subject = "(OSObj" + objectIDstr + ") " + subject;
  414. }
  415. else
  416. {
  417. mmsg.From.Add(MailboxAddress.Parse(objectIDstr + "@" + m_HostName));
  418. mmsg.Subject = subject;
  419. }
  420. mmsg.To.Add(mailTo);
  421. mmsg.Headers["X-Owner-ID"] = ownerID.ToString();
  422. mmsg.Headers["X-Task-ID"] = objectIDstr;
  423. mmsg.Body = new TextPart("plain") {
  424. Text = "Object-Name: " + LastObjectName +
  425. "\nRegion: " + LastObjectRegionName + "\nLocal-Position: " +
  426. LastObjectPosition + "\n\n" + body
  427. };
  428. using (var client = new SmtpClient())
  429. {
  430. if (SMTP_SERVER_TLS)
  431. {
  432. client.ServerCertificateValidationCallback = smptValidateServerCertificate;
  433. client.Connect(SMTP_SERVER_HOSTNAME, SMTP_SERVER_PORT, MailKit.Security.SecureSocketOptions.StartTls);
  434. }
  435. else
  436. client.Connect(SMTP_SERVER_HOSTNAME, SMTP_SERVER_PORT);
  437. if (!string.IsNullOrEmpty(SMTP_SERVER_LOGIN) && !string.IsNullOrEmpty(SMTP_SERVER_PASSWORD))
  438. client.Authenticate(SMTP_SERVER_LOGIN, SMTP_SERVER_PASSWORD);
  439. client.Send(mmsg);
  440. client.Disconnect(true);
  441. }
  442. //Log
  443. m_log.Info("[EMAIL]: EMail sent to: " + address + " from object: " + objectID.ToString() + "@" + m_HostName);
  444. }
  445. catch (Exception e)
  446. {
  447. m_log.Error("[EMAIL]: DefaultEmailModule Exception: " + e.Message);
  448. }
  449. }
  450. else
  451. {
  452. lock (m_primAddressThrottles)
  453. {
  454. if (m_primAddressThrottles.TryGetValue(addressLower, out tci))
  455. {
  456. tci.count += (now - tci.lastTime) * m_MailsToPrimAddressRate;
  457. tci.lastTime = now;
  458. if (tci.count > m_MailsToPrimAddressPerHour)
  459. tci.count = m_MailsToPrimAddressPerHour;
  460. else if (tci.count <= 0)
  461. return;
  462. --tci.count;
  463. }
  464. else
  465. {
  466. tci = new throttleControlInfo
  467. {
  468. lastTime = now,
  469. count = m_MailsToPrimAddressPerHour
  470. };
  471. m_primAddressThrottles[addressLower] = tci;
  472. }
  473. }
  474. // inter object email
  475. int indx = address.IndexOf('@');
  476. if (indx < 0)
  477. return;
  478. if (!UUID.TryParse(address.Substring(0, indx), out UUID toID))
  479. return;
  480. Email email = new Email();
  481. email.time = Util.UnixTimeSinceEpoch().ToString();
  482. email.subject = subject;
  483. email.sender = objectID.ToString() + "@" + m_InterObjectHostname;
  484. email.message = "Object-Name: " + LastObjectName +
  485. "\nRegion: " + LastObjectRegionName + "\nLocal-Position: " +
  486. LastObjectPosition + "\n\n" + body;
  487. if (IsLocal(toID))
  488. {
  489. // object in this instance
  490. InsertEmail(toID, email);
  491. }
  492. else
  493. {
  494. if (!m_enableEmailToExternalObjects)
  495. return;
  496. // object on another region
  497. // TODO FIX
  498. }
  499. }
  500. }
  501. /// <summary>
  502. ///
  503. /// </summary>
  504. /// <param name="objectID"></param>
  505. /// <param name="sender"></param>
  506. /// <param name="subject"></param>
  507. /// <returns></returns>
  508. public Email GetNextEmail(UUID objectID, string sender, string subject)
  509. {
  510. double now = Util.GetTimeStamp();
  511. double lasthour = now - 3600;
  512. lock (m_ownerThrottles)
  513. {
  514. if (m_ownerThrottles.Count > 0 && now > m_nextOwnerThrottlesExpire)
  515. {
  516. List<UUID> removal = new List<UUID>(m_ownerThrottles.Count);
  517. foreach (KeyValuePair<UUID, throttleControlInfo> kpv in m_ownerThrottles)
  518. {
  519. if (kpv.Value.lastTime < lasthour)
  520. removal.Add(kpv.Key);
  521. }
  522. foreach (UUID remove in removal)
  523. m_ownerThrottles.Remove(remove);
  524. m_nextOwnerThrottlesExpire = now + 3600;
  525. }
  526. }
  527. lock (m_primAddressThrottles)
  528. {
  529. if (m_primAddressThrottles.Count > 0 && now > m_nextPrimAddressThrottlesExpire)
  530. {
  531. List<string> removal = new List<string>(m_primAddressThrottles.Count);
  532. foreach (KeyValuePair<string, throttleControlInfo> kpv in m_primAddressThrottles)
  533. {
  534. if (kpv.Value.lastTime < lasthour)
  535. removal.Add(kpv.Key);
  536. }
  537. foreach (string remove in removal)
  538. m_primAddressThrottles.Remove(remove);
  539. m_nextPrimAddressThrottlesExpire = now + 3600;
  540. }
  541. }
  542. lock (m_SMPTAddressThrottles)
  543. {
  544. if (m_SMPTAddressThrottles.Count > 0 && now > m_nextSMTPAddressThrottlesExpire)
  545. {
  546. List<string> removal = new List<string>(m_SMPTAddressThrottles.Count);
  547. foreach (KeyValuePair<string, throttleControlInfo> kpv in m_SMPTAddressThrottles)
  548. {
  549. if (kpv.Value.lastTime < lasthour)
  550. removal.Add(kpv.Key);
  551. }
  552. foreach (string remove in removal)
  553. m_SMPTAddressThrottles.Remove(remove);
  554. m_nextSMTPAddressThrottlesExpire = now + 3600;
  555. }
  556. }
  557. lock (m_queuesLock)
  558. {
  559. m_LastGetEmailCall[objectID] = now + m_QueueTimeout;
  560. if(m_LastGetEmailCall.Count > 1 && now > m_nextQueuesExpire)
  561. {
  562. List<UUID> removal = new List<UUID>(m_LastGetEmailCall.Count);
  563. foreach (KeyValuePair<UUID, double> kpv in m_LastGetEmailCall)
  564. {
  565. if (kpv.Value < now)
  566. removal.Add(kpv.Key);
  567. }
  568. foreach (UUID remove in removal)
  569. {
  570. m_LastGetEmailCall.Remove(remove);
  571. m_MailQueues[remove] = null;
  572. }
  573. m_nextQueuesExpire = now + m_QueueTimeout;
  574. }
  575. m_MailQueues.TryGetValue(objectID, out List<Email> queue);
  576. if (queue != null)
  577. {
  578. lock (queue)
  579. {
  580. if (queue.Count > 0)
  581. {
  582. bool emptySender = string.IsNullOrEmpty(sender);
  583. bool emptySubject = string.IsNullOrEmpty(subject);
  584. int i;
  585. Email ret;
  586. for (i = 0; i < queue.Count; i++)
  587. {
  588. ret = queue[i];
  589. if (emptySender || sender.Equals(ret.sender, StringComparison.InvariantCultureIgnoreCase) &&
  590. (emptySubject || subject.Equals(ret.subject, StringComparison.InvariantCultureIgnoreCase)))
  591. {
  592. if (queue.Count == 1)
  593. {
  594. m_MailQueues[objectID] = null;
  595. m_LastGetEmailCall.Remove(objectID);
  596. ret.numLeft = 0;
  597. }
  598. else
  599. {
  600. queue.RemoveAt(i);
  601. ret.numLeft = queue.Count;
  602. }
  603. return ret;
  604. }
  605. }
  606. }
  607. }
  608. }
  609. }
  610. return null;
  611. }
  612. }
  613. }