http://sourceforge.jp/projects/futonwriter/の旧リポジトリ
Revision | f5bf5f659df1a3d169c28cb5f9aeaae696a5fcc9 (tree) |
---|---|
Zeit | 2011-05-10 19:03:33 |
Autor | azyobuzin <azyobuzin@user...> |
Commiter | azyobuzin |
フォトライフへの投稿に成功。疲れた。WsseAtomConnectionの試行錯誤の結果。
TODO:いろいろ
@@ -75,7 +75,9 @@ | ||
75 | 75 | <SubType>Code</SubType> |
76 | 76 | </Compile> |
77 | 77 | <Compile Include="Models\Hatena\BlogEntry.cs" /> |
78 | + <Compile Include="Models\Hatena\FotolifeEntry.cs" /> | |
78 | 79 | <Compile Include="Models\Hatena\HatenaDiary.cs" /> |
80 | + <Compile Include="Models\Hatena\HatenaFotolife.cs" /> | |
79 | 81 | <Compile Include="Models\Hatena\WsseAtomConnection.cs" /> |
80 | 82 | <Compile Include="Models\Hatena\XmlNamespaces.cs" /> |
81 | 83 | <Compile Include="Models\Model.cs" /> |
@@ -8,7 +8,7 @@ namespace Azyobuzi.HatenaDiaryClient.Models.Hatena | ||
8 | 8 | public class BlogEntry |
9 | 9 | { |
10 | 10 | public DateTime Edited { set; get; } |
11 | - public string BlogPage { set; get; } | |
11 | + public string BlogPageUri { set; get; } | |
12 | 12 | public string Title { set; get; } |
13 | 13 | public string Html { set; get; } |
14 | 14 | public string HatenaSyntax { set; get; } |
@@ -18,7 +18,7 @@ namespace Azyobuzi.HatenaDiaryClient.Models.Hatena | ||
18 | 18 | public BlogEntry(XElement xml) |
19 | 19 | { |
20 | 20 | this.Edited = DateTime.Parse(xml.Element(XmlNamespaces.AtomPub + "edited").Value); |
21 | - this.BlogPage = xml.Elements(XmlNamespaces.Atom + "link") | |
21 | + this.BlogPageUri = xml.Elements(XmlNamespaces.Atom + "link") | |
22 | 22 | .Where(_ => _.Attribute("rel").Value == "alternate") |
23 | 23 | .Select(_ => _.Attribute("href").Value) |
24 | 24 | .FirstOrDefault(); |
@@ -0,0 +1,44 @@ | ||
1 | +using System; | |
2 | +using System.Collections.Generic; | |
3 | +using System.Linq; | |
4 | +using System.Text; | |
5 | +using System.Xml.Linq; | |
6 | +using System.Text.RegularExpressions; | |
7 | + | |
8 | +namespace Azyobuzi.HatenaDiaryClient.Models.Hatena | |
9 | +{ | |
10 | + public class FotolifeEntry | |
11 | + { | |
12 | + public string Title { set; get; } | |
13 | + public string PageUri { set; get; } | |
14 | + public string Id { set; get; } | |
15 | + public DateTime Issued { set; get; } | |
16 | + public string Folder { set; get; } | |
17 | + public string ImageUri { set; get; } | |
18 | + public string ThumbnailUri { set; get; } | |
19 | + public string HatenaSyntax { set; get; } | |
20 | + | |
21 | + public FotolifeEntry() { } | |
22 | + public FotolifeEntry(XElement xml, bool isRdf) | |
23 | + { | |
24 | + if (isRdf) | |
25 | + { | |
26 | + //TODO | |
27 | + } | |
28 | + else | |
29 | + { | |
30 | + this.Title = xml.Element(XmlNamespaces.Atom02Spec + "title").Value; | |
31 | + this.PageUri = xml.Elements(XmlNamespaces.Atom02Spec + "link") | |
32 | + .Where(_ => _.Attribute("rel").Value == "alternate") | |
33 | + .Select(_ => _.Attribute("href").Value) | |
34 | + .FirstOrDefault(); | |
35 | + this.Id = Regex.Match(this.PageUri, @"\d+$").ToString(); | |
36 | + this.Issued = DateTime.Parse(xml.Element(XmlNamespaces.Atom02Spec + "issued").Value); | |
37 | + this.Folder = xml.Element(XmlNamespaces.DublinCore + "subject").Value; | |
38 | + this.ImageUri = xml.Element(XmlNamespaces.HatenaNs + "imageurl").Value; | |
39 | + this.ThumbnailUri = xml.Element(XmlNamespaces.HatenaNs + "imageurlsmall").Value; | |
40 | + this.HatenaSyntax = xml.Element(XmlNamespaces.HatenaNs + "syntax").Value; | |
41 | + } | |
42 | + } | |
43 | + } | |
44 | +} |
@@ -2,6 +2,7 @@ | ||
2 | 2 | using System.Collections.Generic; |
3 | 3 | using System.Linq; |
4 | 4 | using System.Net; |
5 | +using System.Text; | |
5 | 6 | using System.Text.RegularExpressions; |
6 | 7 | using System.Xml.Linq; |
7 | 8 |
@@ -44,6 +45,7 @@ namespace Azyobuzi.HatenaDiaryClient.Models.Hatena | ||
44 | 45 | var reXml = WsseAtomConnection.Post( |
45 | 46 | string.Format("http://d.hatena.ne.jp/{0}/atom/blog", this.userName), |
46 | 47 | CreatePostEntryXml(title, content, updated), |
48 | + Encoding.UTF8, | |
47 | 49 | this.userName, |
48 | 50 | this.password); |
49 | 51 | return new BlogEntry(reXml.Root) |
@@ -66,6 +68,7 @@ namespace Azyobuzi.HatenaDiaryClient.Models.Hatena | ||
66 | 68 | var reXml = WsseAtomConnection.Put( |
67 | 69 | string.Format("http://d.hatena.ne.jp/{0}/atom/blog/{1}", this.userName, dateId), |
68 | 70 | CreatePostEntryXml(title, content, updated), |
71 | + Encoding.UTF8, | |
69 | 72 | this.userName, |
70 | 73 | this.password); |
71 | 74 | return new BlogEntry(reXml.Root) |
@@ -98,6 +101,7 @@ namespace Azyobuzi.HatenaDiaryClient.Models.Hatena | ||
98 | 101 | var reXml = WsseAtomConnection.Post( |
99 | 102 | string.Format("http://d.hatena.ne.jp/{0}/atom/draft", this.userName), |
100 | 103 | CreatePostEntryXml(title, content, updated), |
104 | + Encoding.UTF8, | |
101 | 105 | this.userName, |
102 | 106 | this.password); |
103 | 107 | return new BlogEntry(reXml.Root) |
@@ -120,6 +124,7 @@ namespace Azyobuzi.HatenaDiaryClient.Models.Hatena | ||
120 | 124 | var reXml = WsseAtomConnection.Put( |
121 | 125 | string.Format("http://d.hatena.ne.jp/{0}/atom/draft/{1}", this.userName, id), |
122 | 126 | CreatePostEntryXml(title, content, updated), |
127 | + Encoding.UTF8, | |
123 | 128 | this.userName, |
124 | 129 | this.password); |
125 | 130 | return new BlogEntry(reXml.Root) |
@@ -0,0 +1,90 @@ | ||
1 | +using System; | |
2 | +using System.Collections.Generic; | |
3 | +using System.Linq; | |
4 | +using System.Text; | |
5 | +using System.IO; | |
6 | +using System.Xml.Linq; | |
7 | +using System.Net; | |
8 | + | |
9 | +namespace Azyobuzi.HatenaDiaryClient.Models.Hatena | |
10 | +{ | |
11 | + public class HatenaFotolife | |
12 | + { | |
13 | + private string userName; | |
14 | + private string password; | |
15 | + | |
16 | + public HatenaFotolife(string userName, string password) | |
17 | + { | |
18 | + this.userName = userName; | |
19 | + this.password = password; | |
20 | + } | |
21 | + | |
22 | + public FotolifeEntry Upload(string title, string fileName, string folder = null) | |
23 | + { | |
24 | + string mimeType; | |
25 | + #region MIME Type判断 | |
26 | + switch (Path.GetExtension(fileName).TrimStart('.').ToLower()) | |
27 | + { | |
28 | + case "jpg": | |
29 | + case "jpeg": | |
30 | + mimeType = "image/jpeg"; | |
31 | + break; | |
32 | + case "gif": | |
33 | + mimeType = "image/gif"; | |
34 | + break; | |
35 | + case "png": | |
36 | + mimeType = "image/png"; | |
37 | + break; | |
38 | + case "bmp": | |
39 | + mimeType = "image/x-bmp"; | |
40 | + break; | |
41 | + case "mov": | |
42 | + mimeType = "video/quicktime"; | |
43 | + break; | |
44 | + case "mpg": | |
45 | + case "mpeg": | |
46 | + case "m1v": | |
47 | + mimeType = "video/mpeg"; | |
48 | + break; | |
49 | + case "wmv": | |
50 | + mimeType = "video/x-ms-wmv"; | |
51 | + break; | |
52 | + case "avi": | |
53 | + mimeType = "video/avi"; | |
54 | + break; | |
55 | + case "flv": | |
56 | + mimeType = "video/x-flv"; | |
57 | + break; | |
58 | + case "3gp": | |
59 | + case "3gpp": | |
60 | + mimeType = "video/3gpp"; | |
61 | + break; | |
62 | + case "3g2": | |
63 | + mimeType = "video/3gpp2"; | |
64 | + break; | |
65 | + default: | |
66 | + throw new ArgumentException("対応してないファイルです。"); | |
67 | + } | |
68 | + #endregion | |
69 | + | |
70 | + var entry = new XElement(XmlNamespaces.Atom02Spec + "entry", | |
71 | + new XElement(XmlNamespaces.Atom02Spec + "title", title), | |
72 | + new XElement(XmlNamespaces.Atom02Spec + "content", | |
73 | + new XAttribute("mode", "base64"), | |
74 | + new XAttribute("type", mimeType), | |
75 | + Convert.ToBase64String(File.ReadAllBytes(fileName))) | |
76 | + ); | |
77 | + | |
78 | + if (!string.IsNullOrEmpty(folder)) | |
79 | + entry.Add(new XElement(XmlNamespaces.DublinCore + "subject", folder)); | |
80 | + | |
81 | + var reXml = WsseAtomConnection.Post( | |
82 | + "http://f.hatena.ne.jp/atom/post", | |
83 | + new XDocument(entry), | |
84 | + Encoding.GetEncoding("shift_jis"), | |
85 | + this.userName, | |
86 | + this.password); | |
87 | + return new FotolifeEntry(reXml.Root, false); | |
88 | + } | |
89 | + } | |
90 | +} |
@@ -1,4 +1,5 @@ | ||
1 | 1 | using System; |
2 | +using System.Linq; | |
2 | 3 | using System.Net; |
3 | 4 | using System.Security.Cryptography; |
4 | 5 | using System.Text; |
@@ -12,18 +13,16 @@ namespace Azyobuzi.HatenaDiaryClient.Models.Hatena | ||
12 | 13 | |
13 | 14 | public static string CreateHeader(string userName, string password) |
14 | 15 | { |
15 | - var tmp = new byte[25]; | |
16 | - random.NextBytes(tmp); | |
17 | - var nonce = Convert.ToBase64String(tmp); | |
18 | - tmp = null; | |
16 | + var nonce = new byte[8]; | |
17 | + random.NextBytes(nonce); | |
19 | 18 | var created = DateTime.Now.ToUniversalTime().ToString("o"); |
20 | 19 | var digest = Convert.ToBase64String( |
21 | 20 | new SHA1Managed().ComputeHash( |
22 | - Encoding.ASCII.GetBytes(nonce + created + password) | |
21 | + nonce.Concat(Encoding.ASCII.GetBytes(created)).Concat(Encoding.ASCII.GetBytes(password)).ToArray() | |
23 | 22 | )); |
24 | 23 | return string.Format( |
25 | 24 | @"X-WSSE:UsernameToken Username=""{0}"", PasswordDigest=""{1}"", Nonce=""{2}"", Created=""{3}""", |
26 | - userName, digest, nonce, created); | |
25 | + userName, digest, Convert.ToBase64String(nonce), created); | |
27 | 26 | } |
28 | 27 | |
29 | 28 | public static XDocument Get(string reqUri, string userName, string password) |
@@ -44,13 +43,13 @@ namespace Azyobuzi.HatenaDiaryClient.Models.Hatena | ||
44 | 43 | req.GetResponse().Close(); |
45 | 44 | } |
46 | 45 | |
47 | - private static XDocument PostOrPut(string reqUri, string method, XDocument reqData, string userName, string password) | |
46 | + private static XDocument PostOrPut(string reqUri, string method, XDocument reqData, Encoding enc, string userName, string password) | |
48 | 47 | { |
49 | 48 | var req = WebRequest.Create(reqUri); |
50 | 49 | req.Method = method; |
51 | 50 | req.Headers.Add(CreateHeader(userName, password)); |
52 | - req.ContentType = "application/x.atom+xml; charset=utf-8"; | |
53 | - var bs = Encoding.UTF8.GetBytes(reqData.ToString()); | |
51 | + req.ContentType = "application/x.atom+xml"; | |
52 | + var bs = Encoding.GetEncoding("shift_jis").GetBytes(reqData.ToString()); | |
54 | 53 | req.ContentLength = bs.Length; |
55 | 54 | using (var stream = req.GetRequestStream()) |
56 | 55 | stream.Write(bs, 0, bs.Length); |
@@ -58,14 +57,14 @@ namespace Azyobuzi.HatenaDiaryClient.Models.Hatena | ||
58 | 57 | return XDocument.Load(res.GetResponseStream()); |
59 | 58 | } |
60 | 59 | |
61 | - public static XDocument Post(string reqUri, XDocument reqData, string userName, string password) | |
60 | + public static XDocument Post(string reqUri, XDocument reqData, Encoding enc, string userName, string password) | |
62 | 61 | { |
63 | - return PostOrPut(reqUri, "POST", reqData, userName, password); | |
62 | + return PostOrPut(reqUri, "POST", reqData, enc, userName, password); | |
64 | 63 | } |
65 | 64 | |
66 | - public static XDocument Put(string reqUri, XDocument reqData, string userName, string password) | |
65 | + public static XDocument Put(string reqUri, XDocument reqData, Encoding enc, string userName, string password) | |
67 | 66 | { |
68 | - return PostOrPut(reqUri, "PUT", reqData, userName, password); | |
67 | + return PostOrPut(reqUri, "PUT", reqData, enc, userName, password); | |
69 | 68 | } |
70 | 69 | } |
71 | 70 | } |
\ No newline at end of file |