PageRenderTime 56ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/yafsrc/YAF.Core/Nntp/YafNntp.cs

http://yafnet.codeplex.com
C# | 362 lines | 204 code | 63 blank | 95 comment | 28 complexity | 61ecae22f48e0f9d4a86911765bef612 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, MPL-2.0-no-copyleft-exception, GPL-2.0
  1. /* Yet Another Forum.net
  2. * Copyright (C) 2003-2005 Bj?rnar Henden
  3. * Copyright (C) 2006-2012 Jaben Cargman
  4. * http://www.yetanotherforum.net/
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19. */
  20. namespace YAF.Core.Nntp
  21. {
  22. #region Using
  23. using System;
  24. using System.Data;
  25. using System.Data.SqlClient;
  26. using System.Linq;
  27. using System.Web;
  28. using YAF.Classes.Data;
  29. using YAF.Types;
  30. using YAF.Types.Extensions;
  31. using YAF.Types.Interfaces;
  32. using YAF.Types.Objects;
  33. using YAF.Utils;
  34. #endregion
  35. /// <summary>
  36. /// The on request delegate.
  37. /// </summary>
  38. /// <param name="msg">
  39. /// The msg.
  40. /// </param>
  41. public delegate void OnRequestDelegate(string msg);
  42. /// <summary>
  43. /// The yaf nntp.
  44. /// </summary>
  45. public class YafNntp : INewsreader
  46. {
  47. #region Constants and Fields
  48. /// <summary>
  49. /// The _application state base.
  50. /// </summary>
  51. private readonly HttpApplicationStateBase _applicationStateBase;
  52. #endregion
  53. #region Constructors and Destructors
  54. /// <summary>
  55. /// Initializes a new instance of the <see cref="YafNntp"/> class.
  56. /// </summary>
  57. /// <param name="logger">
  58. /// The logger.
  59. /// </param>
  60. /// <param name="applicationStateBase">
  61. /// The application state base.
  62. /// </param>
  63. public YafNntp([NotNull] ILogger logger, [NotNull] HttpApplicationStateBase applicationStateBase)
  64. {
  65. this._applicationStateBase = applicationStateBase;
  66. this.Logger = logger;
  67. }
  68. #endregion
  69. #region Properties
  70. /// <summary>
  71. /// Gets or sets Logger.
  72. /// </summary>
  73. public ILogger Logger { get; set; }
  74. #endregion
  75. #region Implemented Interfaces
  76. #region INewsreader
  77. /// <summary>
  78. /// The read articles.
  79. /// </summary>
  80. /// <param name="boardID">
  81. /// The board id.
  82. /// </param>
  83. /// <param name="lastUpdate">
  84. /// The n last update.
  85. /// </param>
  86. /// <param name="timeToRun">
  87. /// The n time to run.
  88. /// </param>
  89. /// <param name="createUsers">
  90. /// The b create users.
  91. /// </param>
  92. /// <returns>
  93. /// The read articles.
  94. /// </returns>
  95. /// <exception cref="NntpException"><c>NntpException</c>.</exception>
  96. public int ReadArticles(int boardID, int lastUpdate, int timeToRun, bool createUsers)
  97. {
  98. if (this._applicationStateBase["WorkingInYafNNTP"] != null)
  99. {
  100. return 0;
  101. }
  102. int guestUserId = UserMembershipHelper.GuestUserId; // Use guests user-id
  103. // string hostAddress = YafContext.Current.Get<HttpRequestBase>().UserHostAddress;
  104. DateTime dateTimeStart = DateTime.UtcNow;
  105. int articleCount = 0;
  106. int count = 0;
  107. try
  108. {
  109. this._applicationStateBase["WorkingInYafNNTP"] = true;
  110. // Only those not updated in the last 30 minutes
  111. foreach (var nntpForum in LegacyDb.NntpForumList(boardID, lastUpdate, null, true))
  112. {
  113. using (var nntpConnection = GetNntpConnection(nntpForum))
  114. {
  115. Newsgroup group = nntpConnection.ConnectGroup(nntpForum.GroupName);
  116. var lastMessageNo = nntpForum.LastMessageNo ?? 0;
  117. // start at the bottom...
  118. int currentMessage = lastMessageNo == 0 ? group.Low : lastMessageNo + 1;
  119. var nntpForumID = nntpForum.NntpForumID;
  120. var cutOffDate = nntpForum.DateCutOff ?? DateTime.MinValue;
  121. if (nntpForum.DateCutOff.HasValue)
  122. {
  123. bool behindCutOff = true;
  124. // advance if needed...
  125. do
  126. {
  127. var list = nntpConnection.GetArticleList(currentMessage, Math.Min(currentMessage + 500, group.High));
  128. foreach (var article in list)
  129. {
  130. if (article.Header.Date.Year < 1950 || article.Header.Date > DateTime.UtcNow)
  131. {
  132. article.Header.Date = DateTime.UtcNow;
  133. }
  134. if (article.Header.Date >= cutOffDate)
  135. {
  136. behindCutOff = false;
  137. break;
  138. }
  139. currentMessage++;
  140. }
  141. }
  142. while (behindCutOff);
  143. // update the group lastMessage info...
  144. LegacyDb.nntpforum_update(nntpForum.NntpForumID, currentMessage, guestUserId);
  145. }
  146. for (; currentMessage <= group.High; currentMessage++)
  147. {
  148. Article article;
  149. try
  150. {
  151. try
  152. {
  153. article = nntpConnection.GetArticle(currentMessage);
  154. }
  155. catch (InvalidOperationException ex)
  156. {
  157. Logger.Error(ex, "Error Downloading Message ID {0}", currentMessage);
  158. // just advance to the next message
  159. currentMessage++;
  160. continue;
  161. }
  162. string subject = article.Header.Subject.Trim();
  163. string originalName = article.Header.From.Trim();
  164. string fromName = originalName;
  165. DateTime dateTime = article.Header.Date;
  166. if (dateTime.Year < 1950 || dateTime > DateTime.UtcNow)
  167. {
  168. dateTime = DateTime.UtcNow;
  169. }
  170. if (dateTime < cutOffDate)
  171. {
  172. this.Logger.Debug("Skipped message id {0} due to date being {1}.", currentMessage, dateTime);
  173. continue;
  174. }
  175. if (fromName.IsSet() && fromName.LastIndexOf('<') > 0)
  176. {
  177. fromName = fromName.Substring(0, fromName.LastIndexOf('<') - 1);
  178. fromName = fromName.Replace("\"", String.Empty).Trim();
  179. }
  180. else if (fromName.IsSet() && fromName.LastIndexOf('(') > 0)
  181. {
  182. fromName = fromName.Substring(0, fromName.LastIndexOf('(') - 1).Trim();
  183. }
  184. if (fromName.IsNotSet())
  185. {
  186. fromName = originalName;
  187. }
  188. string externalMessageId = article.MessageId;
  189. string referenceId = article.Header.ReferenceIds.LastOrDefault();
  190. if (createUsers)
  191. {
  192. guestUserId = LegacyDb.user_nntp(boardID, fromName, string.Empty, article.Header.TimeZoneOffset);
  193. }
  194. string body = this.ReplaceBody(article.Body.Text.Trim());
  195. LegacyDb.nntptopic_savemessage(
  196. nntpForumID,
  197. subject.Truncate(75),
  198. body,
  199. guestUserId,
  200. fromName.Truncate(100, String.Empty),
  201. "NNTP",
  202. dateTime,
  203. externalMessageId.Truncate(255, String.Empty),
  204. referenceId.Truncate(255, String.Empty));
  205. lastMessageNo = currentMessage;
  206. articleCount++;
  207. // We don't wanna retrieve articles forever...
  208. // Total time x seconds for all groups
  209. if ((DateTime.UtcNow - dateTimeStart).TotalSeconds > timeToRun)
  210. {
  211. break;
  212. }
  213. if (count++ > 1000)
  214. {
  215. count = 0;
  216. LegacyDb.nntpforum_update(nntpForum.NntpForumID, lastMessageNo, guestUserId);
  217. }
  218. }
  219. catch (NntpException exception)
  220. {
  221. if (exception.ErrorCode >= 900)
  222. {
  223. throw;
  224. }
  225. else if (exception.ErrorCode != 423)
  226. {
  227. this.Logger.Error(exception, "YafNntp");
  228. }
  229. }
  230. catch (SqlException exception)
  231. {
  232. this.Logger.Error(exception, "YafNntp DB Failure");
  233. }
  234. }
  235. LegacyDb.nntpforum_update(nntpForum.NntpForumID, lastMessageNo, guestUserId);
  236. // Total time x seconds for all groups
  237. if ((DateTime.UtcNow - dateTimeStart).TotalSeconds > timeToRun)
  238. {
  239. break;
  240. }
  241. }
  242. }
  243. }
  244. finally
  245. {
  246. this._applicationStateBase["WorkingInYafNNTP"] = null;
  247. }
  248. return articleCount;
  249. }
  250. [NotNull]
  251. public static NntpConnection GetNntpConnection([NotNull] TypedNntpForum nntpForum)
  252. {
  253. CodeContracts.ArgumentNotNull(nntpForum, "nntpForum");
  254. var nntpConnection = new NntpConnection();
  255. // call connect server
  256. nntpConnection.ConnectServer(nntpForum.Address.ToLower(), nntpForum.Port ?? 119);
  257. // provide authentication if required...
  258. if (nntpForum.UserName.IsSet() && nntpForum.UserPass.IsSet())
  259. {
  260. nntpConnection.ProvideIdentity(nntpForum.UserName, nntpForum.UserPass);
  261. nntpConnection.SendIdentity();
  262. }
  263. return nntpConnection;
  264. }
  265. #endregion
  266. #endregion
  267. #region Methods
  268. /// <summary>
  269. /// The replace body.
  270. /// </summary>
  271. /// <param name="body">
  272. /// The body.
  273. /// </param>
  274. /// <returns>
  275. /// The replace body.
  276. /// </returns>
  277. [NotNull]
  278. private string ReplaceBody([NotNull] string body)
  279. {
  280. // Incorrect tags fixes which are common in nntp messages and cause display problems.
  281. // These are spotted ones.
  282. body = body.Replace("<br>", "<br />");
  283. body = body.Replace("<hr>", "<hr />");
  284. // body = "Date: {0}\r\n\r\n".FormatWith(article.Header.Date) + body;
  285. // body = "Date parsed: {0}(UTC)\r\n".FormatWith(dateTime) + body;
  286. //// vzrus: various wrong NNTP tags replacements
  287. // body = body.Replace("&amp;lt;", "&lt;");
  288. // body = body.Replace("&amp;gt;", "&gt;");
  289. // body = body.Replace("&lt;br&gt;", "");
  290. // body = body.Replace("&lt;hr&gt;", "<hr />");
  291. // body = body.Replace("&amp;quot;", @"&#34;");
  292. // Innerquote class in yaf terms, should be replaced while displaying
  293. // body = body.Replace("&lt;quote&gt;", @"[quote]");
  294. // body = body.Replace("&lt;/quote&gt;", @"[/quote]");
  295. return body;
  296. }
  297. #endregion
  298. }
  299. }