PageRenderTime 40ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/BlogEngine/DotNetSlave.BusinessLogic/API/MetaWeblog/XMLRPCRequest.cs

#
C# | 508 lines | 304 code | 65 blank | 139 comment | 56 complexity | e2dabc8553c7ffcded96993ceec14f6e MD5 | raw file
Possible License(s): LGPL-2.1, Apache-2.0, BSD-3-Clause
  1. namespace BlogEngine.Core.API.MetaWeblog
  2. {
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Diagnostics;
  6. using System.Globalization;
  7. using System.Linq;
  8. using System.Text;
  9. using System.Web;
  10. using System.Xml;
  11. /// <summary>
  12. /// Obejct is the incoming XML-RPC Request. Handles parsing the XML-RPC and
  13. /// fills its properties with the values sent in the request.
  14. /// </summary>
  15. internal class XMLRPCRequest
  16. {
  17. #region Constants and Fields
  18. /// <summary>
  19. /// The input params.
  20. /// </summary>
  21. private List<XmlNode> inputParams;
  22. #endregion
  23. #region Constructors and Destructors
  24. /// <summary>
  25. /// Initializes a new instance of the <see cref="XMLRPCRequest"/> class.
  26. /// Loads XMLRPCRequest object from HttpContext
  27. /// </summary>
  28. /// <param name="input">
  29. /// incoming HttpContext
  30. /// </param>
  31. public XMLRPCRequest(HttpContext input)
  32. {
  33. var inputXml = ParseRequest(input);
  34. // LogMetaWeblogCall(inputXml);
  35. this.LoadXmlRequest(inputXml); // Loads Method Call and Associated Variables
  36. }
  37. #endregion
  38. #region Properties
  39. /// <summary>
  40. /// Gets AppKey is a key generated by the calling application. It is sent with blogger API calls.
  41. /// </summary>
  42. /// <remarks>
  43. /// BlogEngine.NET doesn't require specific AppKeys for API calls. It is no longer standard practive.
  44. /// </remarks>
  45. public string AppKey { get; private set; }
  46. /// <summary>
  47. /// Gets ID of the Blog to call the function on. Since BlogEngine supports only a single blog instance,
  48. /// this incoming parameter is not used.
  49. /// </summary>
  50. public string BlogID { get; private set; }
  51. /// <summary>
  52. /// Gets MediaObject is a struct sent by the metaWeblog.newMediaObject function.
  53. /// It contains information about the media and the object in a bit array.
  54. /// </summary>
  55. public MWAMediaObject MediaObject { get; private set; }
  56. /// <summary>
  57. /// Gets Name of Called Metaweblog Function
  58. /// </summary>
  59. public string MethodName { get; private set; }
  60. /// <summary>
  61. /// Gets Number of post request by the metaWeblog.getRecentPosts function
  62. /// </summary>
  63. public int NumberOfPosts { get; private set; }
  64. /// <summary>
  65. /// Gets Metaweblog Page Struct
  66. /// </summary>
  67. public MWAPage Page { get; private set; }
  68. /// <summary>
  69. /// Gets PageID Guid in string format
  70. /// </summary>
  71. public string PageID { get; private set; }
  72. /// <summary>
  73. /// Gets Password for user validation
  74. /// </summary>
  75. public string Password { get; private set; }
  76. /// <summary>
  77. /// Gets Metaweblog Post struct containing information post including title, content, and categories.
  78. /// </summary>
  79. public MWAPost Post { get; private set; }
  80. /// <summary>
  81. /// Gets The PostID Guid in string format
  82. /// </summary>
  83. public string PostID { get; private set; }
  84. /// <summary>
  85. /// Gets a value indicating whether or not a post will be marked as published by BlogEngine.
  86. /// </summary>
  87. public bool Publish { get; private set; }
  88. /// <summary>
  89. /// Gets Login for user validation
  90. /// </summary>
  91. public string UserName { get; private set; }
  92. #endregion
  93. #region Methods
  94. /// <summary>
  95. /// Creates a Metaweblog Media object from the XML struct
  96. /// </summary>
  97. /// <param name="node">
  98. /// XML contains a Metaweblog MediaObject Struct
  99. /// </param>
  100. /// <returns>
  101. /// Metaweblog MediaObject Struct Obejct
  102. /// </returns>
  103. private static MWAMediaObject GetMediaObject(XmlNode node)
  104. {
  105. var name = node.SelectSingleNode("value/struct/member[name='name']");
  106. var type = node.SelectSingleNode("value/struct/member[name='type']");
  107. var bits = node.SelectSingleNode("value/struct/member[name='bits']");
  108. var temp = new MWAMediaObject
  109. {
  110. name = name == null ? string.Empty : name.LastChild.InnerText,
  111. type = type == null ? "notsent" : type.LastChild.InnerText,
  112. bits = Convert.FromBase64String(bits == null ? string.Empty : bits.LastChild.InnerText)
  113. };
  114. return temp;
  115. }
  116. /// <summary>
  117. /// Creates a Metaweblog Page object from the XML struct
  118. /// </summary>
  119. /// <param name="node">
  120. /// XML contains a Metaweblog Page Struct
  121. /// </param>
  122. /// <returns>
  123. /// Metaweblog Page Struct Obejct
  124. /// </returns>
  125. private static MWAPage GetPage(XmlNode node)
  126. {
  127. var temp = new MWAPage();
  128. // Require Title and Description
  129. var title = node.SelectSingleNode("value/struct/member[name='title']");
  130. if (title == null)
  131. {
  132. throw new MetaWeblogException("06", "Page Struct Element, Title, not Sent.");
  133. }
  134. temp.title = title.LastChild.InnerText;
  135. var description = node.SelectSingleNode("value/struct/member[name='description']");
  136. if (description == null)
  137. {
  138. throw new MetaWeblogException("06", "Page Struct Element, Description, not Sent.");
  139. }
  140. temp.description = description.LastChild.InnerText;
  141. var link = node.SelectSingleNode("value/struct/member[name='link']");
  142. if (link != null)
  143. {
  144. temp.link = node.SelectSingleNode("value/struct/member[name='link']") == null ? null : link.LastChild.InnerText;
  145. }
  146. var dateCreated = node.SelectSingleNode("value/struct/member[name='dateCreated']");
  147. if (dateCreated != null)
  148. {
  149. try
  150. {
  151. var tempDate = dateCreated.LastChild.InnerText;
  152. temp.pageDate = DateTime.ParseExact(
  153. tempDate,
  154. "yyyyMMdd'T'HH':'mm':'ss",
  155. CultureInfo.InvariantCulture,
  156. DateTimeStyles.AssumeUniversal);
  157. }
  158. catch (Exception ex)
  159. {
  160. // Ignore PubDate Error
  161. Debug.WriteLine(ex.Message);
  162. }
  163. }
  164. // Keywords
  165. var keywords = node.SelectSingleNode("value/struct/member[name='mt_keywords']");
  166. temp.mt_keywords = keywords == null ? string.Empty : keywords.LastChild.InnerText;
  167. var pageParentId = node.SelectSingleNode("value/struct/member[name='wp_page_parent_id']");
  168. temp.pageParentID = pageParentId == null ? null : pageParentId.LastChild.InnerText;
  169. return temp;
  170. }
  171. /// <summary>
  172. /// Creates a Metaweblog Post object from the XML struct
  173. /// </summary>
  174. /// <param name="node">
  175. /// XML contains a Metaweblog Post Struct
  176. /// </param>
  177. /// <returns>
  178. /// Metaweblog Post Struct Obejct
  179. /// </returns>
  180. private static MWAPost GetPost(XmlNode node)
  181. {
  182. var temp = new MWAPost();
  183. // Require Title and Description
  184. var title = node.SelectSingleNode("value/struct/member[name='title']");
  185. if (title == null)
  186. {
  187. throw new MetaWeblogException("05", "Page Struct Element, Title, not Sent.");
  188. }
  189. temp.title = title.LastChild.InnerText;
  190. var description = node.SelectSingleNode("value/struct/member[name='description']");
  191. if (description == null)
  192. {
  193. throw new MetaWeblogException("05", "Page Struct Element, Description, not Sent.");
  194. }
  195. temp.description = description.LastChild.InnerText;
  196. var link = node.SelectSingleNode("value/struct/member[name='link']");
  197. temp.link = link == null ? string.Empty : link.LastChild.InnerText;
  198. var allowComments = node.SelectSingleNode("value/struct/member[name='mt_allow_comments']");
  199. temp.commentPolicy = allowComments == null ? string.Empty : allowComments.LastChild.InnerText;
  200. var excerpt = node.SelectSingleNode("value/struct/member[name='mt_excerpt']");
  201. temp.excerpt = excerpt == null ? string.Empty : excerpt.LastChild.InnerText;
  202. var slug = node.SelectSingleNode("value/struct/member[name='wp_slug']");
  203. temp.slug = slug == null ? string.Empty : slug.LastChild.InnerText;
  204. var authorId = node.SelectSingleNode("value/struct/member[name='wp_author_id']");
  205. temp.author = authorId == null ? string.Empty : authorId.LastChild.InnerText;
  206. var cats = new List<string>();
  207. var categories = node.SelectSingleNode("value/struct/member[name='categories']");
  208. if (categories != null)
  209. {
  210. var categoryArray = categories.LastChild;
  211. var categoryArrayNodes = categoryArray.SelectNodes("array/data/value/string");
  212. if (categoryArrayNodes != null)
  213. {
  214. cats.AddRange(categoryArrayNodes.Cast<XmlNode>().Select(
  215. catnode => catnode.InnerText));
  216. }
  217. }
  218. temp.categories = cats;
  219. // postDate has a few different names to worry about
  220. var dateCreated = node.SelectSingleNode("value/struct/member[name='dateCreated']");
  221. var pubDate = node.SelectSingleNode("value/struct/member[name='pubDate']");
  222. if (dateCreated != null)
  223. {
  224. try
  225. {
  226. var tempDate = dateCreated.LastChild.InnerText;
  227. temp.postDate = DateTime.ParseExact(
  228. tempDate,
  229. "yyyyMMdd'T'HH':'mm':'ss",
  230. CultureInfo.InvariantCulture,
  231. DateTimeStyles.AssumeUniversal);
  232. }
  233. catch (Exception ex)
  234. {
  235. // Ignore PubDate Error
  236. Debug.WriteLine(ex.Message);
  237. }
  238. }
  239. else if (pubDate != null)
  240. {
  241. try
  242. {
  243. var tempPubDate = pubDate.LastChild.InnerText;
  244. temp.postDate = DateTime.ParseExact(
  245. tempPubDate,
  246. "yyyyMMdd'T'HH':'mm':'ss",
  247. CultureInfo.InvariantCulture,
  248. DateTimeStyles.AssumeUniversal);
  249. }
  250. catch (Exception ex)
  251. {
  252. // Ignore PubDate Error
  253. Debug.WriteLine(ex.Message);
  254. }
  255. }
  256. // WLW tags implementation using mt_keywords
  257. var tags = new List<string>();
  258. var keywords = node.SelectSingleNode("value/struct/member[name='mt_keywords']");
  259. if (keywords != null)
  260. {
  261. var tagsList = keywords.LastChild.InnerText;
  262. foreach (var item in
  263. tagsList.Split(',').Where(item => string.IsNullOrEmpty(tags.Find(t => t.Equals(item.Trim(), StringComparison.OrdinalIgnoreCase)))))
  264. {
  265. tags.Add(item.Trim());
  266. }
  267. }
  268. temp.tags = tags;
  269. return temp;
  270. }
  271. /// <summary>
  272. /// Loads object properties with contents of passed xml
  273. /// </summary>
  274. /// <param name="xml">
  275. /// xml doc with methodname and parameters
  276. /// </param>
  277. private void LoadXmlRequest(string xml)
  278. {
  279. var request = new XmlDocument();
  280. try
  281. {
  282. if (!(xml.StartsWith("<?xml") || xml.StartsWith("<method")))
  283. {
  284. xml = xml.Substring(xml.IndexOf("<?xml"));
  285. }
  286. request.LoadXml(xml);
  287. }
  288. catch (Exception ex)
  289. {
  290. throw new MetaWeblogException("01", string.Format("Invalid XMLRPC Request. ({0})", ex.Message));
  291. }
  292. // Method name is always first
  293. if (request.DocumentElement != null)
  294. {
  295. this.MethodName = request.DocumentElement.ChildNodes[0].InnerText;
  296. }
  297. // Parameters are next (and last)
  298. var xmlParams = request.SelectNodes("/methodCall/params/param");
  299. if (xmlParams != null)
  300. {
  301. this.inputParams = xmlParams.Cast<XmlNode>().ToList();
  302. }
  303. // Determine what params are what by method name
  304. switch (this.MethodName)
  305. {
  306. case "metaWeblog.newPost":
  307. this.BlogID = this.inputParams[0].InnerText;
  308. this.UserName = this.inputParams[1].InnerText;
  309. this.Password = this.inputParams[2].InnerText;
  310. this.Post = GetPost(this.inputParams[3]);
  311. this.Publish = this.inputParams[4].InnerText != "0" && this.inputParams[4].InnerText != "false";
  312. break;
  313. case "metaWeblog.editPost":
  314. this.PostID = this.inputParams[0].InnerText;
  315. this.UserName = this.inputParams[1].InnerText;
  316. this.Password = this.inputParams[2].InnerText;
  317. this.Post = GetPost(this.inputParams[3]);
  318. this.Publish = this.inputParams[4].InnerText != "0" && this.inputParams[4].InnerText != "false";
  319. break;
  320. case "metaWeblog.getPost":
  321. this.PostID = this.inputParams[0].InnerText;
  322. this.UserName = this.inputParams[1].InnerText;
  323. this.Password = this.inputParams[2].InnerText;
  324. break;
  325. case "metaWeblog.newMediaObject":
  326. this.BlogID = this.inputParams[0].InnerText;
  327. this.UserName = this.inputParams[1].InnerText;
  328. this.Password = this.inputParams[2].InnerText;
  329. this.MediaObject = GetMediaObject(this.inputParams[3]);
  330. break;
  331. case "metaWeblog.getCategories":
  332. case "wp.getAuthors":
  333. case "wp.getPageList":
  334. case "wp.getPages":
  335. case "wp.getTags":
  336. this.BlogID = this.inputParams[0].InnerText;
  337. this.UserName = this.inputParams[1].InnerText;
  338. this.Password = this.inputParams[2].InnerText;
  339. break;
  340. case "metaWeblog.getRecentPosts":
  341. this.BlogID = this.inputParams[0].InnerText;
  342. this.UserName = this.inputParams[1].InnerText;
  343. this.Password = this.inputParams[2].InnerText;
  344. this.NumberOfPosts = Int32.Parse(this.inputParams[3].InnerText, CultureInfo.InvariantCulture);
  345. break;
  346. case "blogger.getUsersBlogs":
  347. case "metaWeblog.getUsersBlogs":
  348. this.AppKey = this.inputParams[0].InnerText;
  349. this.UserName = this.inputParams[1].InnerText;
  350. this.Password = this.inputParams[2].InnerText;
  351. break;
  352. case "blogger.deletePost":
  353. this.AppKey = this.inputParams[0].InnerText;
  354. this.PostID = this.inputParams[1].InnerText;
  355. this.UserName = this.inputParams[2].InnerText;
  356. this.Password = this.inputParams[3].InnerText;
  357. this.Publish = this.inputParams[4].InnerText != "0" && this.inputParams[4].InnerText != "false";
  358. break;
  359. case "blogger.getUserInfo":
  360. this.AppKey = this.inputParams[0].InnerText;
  361. this.UserName = this.inputParams[1].InnerText;
  362. this.Password = this.inputParams[2].InnerText;
  363. break;
  364. case "wp.newPage":
  365. this.BlogID = this.inputParams[0].InnerText;
  366. this.UserName = this.inputParams[1].InnerText;
  367. this.Password = this.inputParams[2].InnerText;
  368. this.Page = GetPage(this.inputParams[3]);
  369. this.Publish = this.inputParams[4].InnerText != "0" && this.inputParams[4].InnerText != "false";
  370. break;
  371. case "wp.getPage":
  372. this.BlogID = this.inputParams[0].InnerText;
  373. this.PageID = this.inputParams[1].InnerText;
  374. this.UserName = this.inputParams[2].InnerText;
  375. this.Password = this.inputParams[3].InnerText;
  376. break;
  377. case "wp.editPage":
  378. this.BlogID = this.inputParams[0].InnerText;
  379. this.PageID = this.inputParams[1].InnerText;
  380. this.UserName = this.inputParams[2].InnerText;
  381. this.Password = this.inputParams[3].InnerText;
  382. this.Page = GetPage(this.inputParams[4]);
  383. this.Publish = this.inputParams[5].InnerText != "0" && this.inputParams[5].InnerText != "false";
  384. break;
  385. case "wp.deletePage":
  386. this.BlogID = this.inputParams[0].InnerText;
  387. this.UserName = this.inputParams[1].InnerText;
  388. this.Password = this.inputParams[2].InnerText;
  389. this.PageID = this.inputParams[3].InnerText;
  390. break;
  391. default:
  392. throw new MetaWeblogException("02", string.Format("Unknown Method. ({0})", this.MethodName));
  393. }
  394. }
  395. /*
  396. /// <summary>
  397. /// The log meta weblog call.
  398. /// </summary>
  399. /// <param name="message">
  400. /// The message.
  401. /// </param>
  402. private void LogMetaWeblogCall(string message)
  403. {
  404. var saveFolder = HttpContext.Current.Server.MapPath(BlogSettings.Instance.StorageLocation);
  405. var saveFile = Path.Combine(saveFolder, "lastmetaweblogcall.txt");
  406. try
  407. {
  408. // Save message to file
  409. using (var fileWrtr = new FileStream(saveFile, FileMode.OpenOrCreate, FileAccess.Write))
  410. {
  411. using (var streamWrtr = new StreamWriter(fileWrtr))
  412. {
  413. streamWrtr.WriteLine(message);
  414. }
  415. }
  416. }
  417. catch
  418. {
  419. // Ignore all errors
  420. }
  421. }
  422. */
  423. /// <summary>
  424. /// Retrieves the content of the input stream
  425. /// and return it as plain text.
  426. /// </summary>
  427. /// <param name="context">
  428. /// The context.
  429. /// </param>
  430. /// <returns>
  431. /// The parse request.
  432. /// </returns>
  433. private static string ParseRequest(HttpContext context)
  434. {
  435. var buffer = new byte[context.Request.InputStream.Length];
  436. context.Request.InputStream.Position = 0;
  437. context.Request.InputStream.Read(buffer, 0, buffer.Length);
  438. return Encoding.UTF8.GetString(buffer);
  439. }
  440. #endregion
  441. }
  442. }