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