OSDN Git Service

PostClass.CreatedAtの型をDateTimeUtcに変更
[opentween/open-tween.git] / OpenTween / Growl.cs
1 // OpenTween - Client of Twitter
2 // Copyright (c) 2007-2011 kiri_feather (@kiri_feather) <kiri.feather@gmail.com>
3 //           (c) 2008-2011 Moz (@syo68k)
4 //           (c) 2008-2011 takeshik (@takeshik) <http://www.takeshik.org/>
5 //           (c) 2010-2011 anis774 (@anis774) <http://d.hatena.ne.jp/anis774/>
6 //           (c) 2010-2011 fantasticswallow (@f_swallow) <http://twitter.com/f_swallow>
7 //           (c) 2011      kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
8 // All rights reserved.
9 // 
10 // This file is part of OpenTween.
11 // 
12 // This program is free software; you can redistribute it and/or modify it
13 // under the terms of the GNU General public License as published by the Free
14 // Software Foundation; either version 3 of the License, or (at your option)
15 // any later version.
16 // 
17 // This program is distributed in the hope that it will be useful, but
18 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General public License
20 // for more details. 
21 // 
22 // You should have received a copy of the GNU General public License along
23 // with this program. If not, see <http://www.gnu.org/licenses/>, or write to
24 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
25 // Boston, MA 02110-1301, USA.
26
27 using System;
28 using System.Collections.Generic;
29 using System.Linq;
30 using System.Text;
31 using System.Reflection;
32 using System.IO;
33 using System.Drawing;
34 using System.Drawing.Imaging;
35 using System.Windows.Forms;
36 using System.ComponentModel;
37 using System.Collections;
38 using System.Globalization;
39
40 namespace OpenTween
41 {
42     public class GrowlHelper
43     {
44         private Assembly _connector = null;
45         private Assembly _core = null;
46
47         private object _growlNTreply;
48         private object _growlNTdm;
49         private object _growlNTnew;
50         private object _growlNTusevent;
51         private object _growlApp;
52
53         private object _targetConnector;
54
55         private string _appName = "";
56         bool _initialized = false;
57
58         public class NotifyCallbackEventArgs : EventArgs
59         {
60             public long StatusId { get; set; }
61             public NotifyType NotifyType { get; set; }
62             public NotifyCallbackEventArgs(NotifyType notifyType, string statusId)
63             {
64                 if (statusId.Length > 1)
65                 {
66                     this.StatusId = long.Parse(statusId);
67                     this.NotifyType = notifyType;
68                 }
69             }
70         }
71
72         public event EventHandler<NotifyCallbackEventArgs> NotifyClicked;
73
74         public string AppName
75         {
76             get { return _appName; }
77         }
78
79         public enum NotifyType
80         {
81             Reply = 0,
82             DirectMessage = 1,
83             Notify = 2,
84             UserStreamEvent = 3,
85         }
86
87         public GrowlHelper(string appName)
88         {
89             _appName = appName;
90         }
91
92         public bool IsAvailable
93         {
94             get
95             {
96                 if (_connector == null || _core == null || !_initialized)
97                     return false;
98                 else
99                     return true;
100             }
101         }
102
103         private byte[] IconToByteArray(string filename)
104         {
105             using (Icon ic = new Icon(filename))
106             {
107                 return IconToByteArray(ic);
108             }
109         }
110
111         private byte[] IconToByteArray(Icon icondata)
112         {
113             using (MemoryStream ms = new MemoryStream())
114             {
115                 using (Icon ic = new Icon(icondata, 48, 48))
116                 {
117                     ic.ToBitmap().Save(ms, ImageFormat.Png);
118                     return ms.ToArray();
119                 }
120             }
121         }
122
123         public static bool IsDllExists
124         {
125             get
126             {
127                 string dir = Application.StartupPath;
128                 string connectorPath = Path.Combine(dir, "Growl.Connector.dll");
129                 string corePath = Path.Combine(dir, "Growl.CoreLibrary.dll");
130                 if (File.Exists(connectorPath) && File.Exists(corePath))
131                     return true;
132                 else
133                     return false;
134             }
135         }
136
137         public bool RegisterGrowl()
138         {
139             _initialized = false;
140             string dir = Application.StartupPath;
141             string connectorPath = Path.Combine(dir, "Growl.Connector.dll");
142             string corePath = Path.Combine(dir, "Growl.CoreLibrary.dll");
143
144             try
145             {
146                 if (!IsDllExists) return false;
147                 _connector = Assembly.LoadFile(connectorPath);
148                 _core = Assembly.LoadFile(corePath);
149             }
150             catch (Exception)
151             {
152                 return false;
153             }
154
155             try
156             {
157                 _targetConnector = _connector.CreateInstance("Growl.Connector.GrowlConnector");
158                 Type _t = _connector.GetType("Growl.Connector.NotificationType");
159
160                 _growlNTreply = _t.InvokeMember(null,
161                     BindingFlags.CreateInstance, null, null, new object[] { "REPLY", "Reply" }, CultureInfo.InvariantCulture);
162
163                 _growlNTdm = _t.InvokeMember(null,
164                     BindingFlags.CreateInstance, null, null, new object[] { "DIRECT_MESSAGE", "DirectMessage" }, CultureInfo.InvariantCulture);
165
166                 _growlNTnew = _t.InvokeMember(null,
167                     BindingFlags.CreateInstance, null, null, new object[] { "NOTIFY", "新着通知" }, CultureInfo.InvariantCulture);
168
169                 _growlNTusevent = _t.InvokeMember(null,
170                     BindingFlags.CreateInstance, null, null, new object[] { "USERSTREAM_EVENT", "UserStream Event" }, CultureInfo.InvariantCulture);
171
172                 object encryptType =
173                         _connector.GetType("Growl.Connector.Cryptography+SymmetricAlgorithmType").InvokeMember(
174                             "PlainText", BindingFlags.GetField, null, null, null, CultureInfo.InvariantCulture);
175                 _targetConnector.GetType().InvokeMember("EncryptionAlgorithm", BindingFlags.SetProperty, null, _targetConnector, new object[] { encryptType }, CultureInfo.InvariantCulture);
176
177                 _growlApp = _connector.CreateInstance(
178                     "Growl.Connector.Application", false, BindingFlags.Default, null, new object[] { _appName }, null, null);
179
180
181                 if (File.Exists(Path.Combine(Application.StartupPath, "Icons\\Tween.png")))
182                 {
183                     // Icons\Tween.pngを使用
184                     ConstructorInfo ci = _core.GetType(
185                         "Growl.CoreLibrary.Resource").GetConstructor(
186                         BindingFlags.NonPublic | BindingFlags.Instance,
187                         null, new Type[] { typeof(string) }, null);
188
189                     object data = ci.Invoke(new object[] { Path.Combine(Application.StartupPath, "Icons\\Tween.png") });
190                     PropertyInfo pi = _growlApp.GetType().GetProperty("Icon");
191                     pi.SetValue(_growlApp, data, null);
192
193                 }
194                 else if (File.Exists(Path.Combine(Application.StartupPath, "Icons\\MIcon.ico")))
195                 {
196                     // アイコンセットにMIcon.icoが存在する場合それを使用
197                     ConstructorInfo cibd = _core.GetType(
198                         "Growl.CoreLibrary.BinaryData").GetConstructor(
199                         BindingFlags.Public | BindingFlags.Instance,
200                         null, new Type[] { typeof(byte[]) }, null);
201                     object bdata = cibd.Invoke(
202                         new object[] { IconToByteArray(Path.Combine(Application.StartupPath, "Icons\\MIcon.ico")) });
203
204                     ConstructorInfo ciRes = _core.GetType(
205                         "Growl.CoreLibrary.Resource").GetConstructor(
206                         BindingFlags.NonPublic | BindingFlags.Instance,
207                         null, new Type[] { bdata.GetType() }, null);
208
209                     object data = ciRes.Invoke(new object[] { bdata });
210                     PropertyInfo pi = _growlApp.GetType().GetProperty("Icon");
211                     pi.SetValue(_growlApp, data, null);
212                 }
213                 else
214                 {
215                     //内蔵アイコンリソースを使用
216                     ConstructorInfo cibd = _core.GetType(
217                         "Growl.CoreLibrary.BinaryData").GetConstructor(
218                         BindingFlags.Public | BindingFlags.Instance,
219                         null, new Type[] { typeof(byte[]) }, null);
220                     object bdata = cibd.Invoke(
221                         new object[] { IconToByteArray(Properties.Resources.MIcon) });
222
223                     ConstructorInfo ciRes = _core.GetType(
224                         "Growl.CoreLibrary.Resource").GetConstructor(
225                         BindingFlags.NonPublic | BindingFlags.Instance,
226                         null, new Type[] { bdata.GetType() }, null);
227
228                     object data = ciRes.Invoke(new object[] { bdata });
229                     PropertyInfo pi = _growlApp.GetType().GetProperty("Icon");
230                     pi.SetValue(_growlApp, data, null);
231                 }
232
233                 MethodInfo mi = _targetConnector.GetType().GetMethod("Register", new Type[] { _growlApp.GetType(), _connector.GetType("Growl.Connector.NotificationType[]") });
234
235                 _t = _connector.GetType("Growl.Connector.NotificationType");
236
237                 ArrayList arglist = new ArrayList();
238                 arglist.Add(_growlNTreply);
239                 arglist.Add(_growlNTdm);
240                 arglist.Add(_growlNTnew);
241                 arglist.Add(_growlNTusevent);
242
243                 mi.Invoke(_targetConnector, new object[] { _growlApp, arglist.ToArray(_t) });
244
245                 // コールバックメソッドの登録
246                 Type tGrowlConnector = _connector.GetType("Growl.Connector.GrowlConnector");
247                 EventInfo evNotificationCallback = tGrowlConnector.GetEvent("NotificationCallback");
248                 Type tDelegate = evNotificationCallback.EventHandlerType;
249                 MethodInfo miHandler = typeof(GrowlHelper).GetMethod("GrowlCallbackHandler", BindingFlags.NonPublic | BindingFlags.Instance);
250                 Delegate d = Delegate.CreateDelegate(tDelegate, this, miHandler);
251                 MethodInfo miAddHandler = evNotificationCallback.GetAddMethod();
252                 object[] addHandlerArgs = { d };
253                 miAddHandler.Invoke(_targetConnector, addHandlerArgs);
254
255                 _initialized = true;
256             }
257             catch (Exception)
258             {
259                 _initialized = false;
260                 return false;
261             }
262
263             return true;
264         }
265
266         public void Notify(NotifyType notificationType, string id, string title, string text, Image icon = null, string url = "")
267         {
268             if (!_initialized) return;
269             string notificationName = "";
270             switch (notificationType)
271             {
272                 case NotifyType.Reply:
273                     notificationName = "REPLY";
274                     break;
275                 case NotifyType.DirectMessage:
276                     notificationName = "DIRECT_MESSAGE";
277                     break;
278                 case NotifyType.Notify:
279                     notificationName = "NOTIFY";
280                     break;
281                 case NotifyType.UserStreamEvent:
282                     notificationName = "USERSTREAM_EVENT";
283                     break;
284             }
285             object n = null;
286             if (icon != null || !string.IsNullOrEmpty(url))
287             {
288                 Type gCore = _core.GetType("Growl.CoreLibrary.Resource");
289                 object res = null;
290                 if (icon != null)
291                 {
292                     res = gCore.InvokeMember("op_Implicit",
293                                              BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod,
294                                              null,
295                                              null,
296                                              new object[] { icon },
297                                              CultureInfo.InvariantCulture);
298                 }
299                 else
300                 {
301                     res = gCore.InvokeMember("op_Implicit",
302                                              BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod,
303                                              null,
304                                              null,
305                                              new object[] { url },
306                                              CultureInfo.InvariantCulture);
307                 }
308                 object priority =
309                         _connector.GetType("Growl.Connector.Priority").InvokeMember(
310                             "Normal", BindingFlags.GetField, null, null, null, CultureInfo.InvariantCulture);
311                 n = _connector.GetType("Growl.Connector.Notification").InvokeMember(
312                         "Notification",
313                         BindingFlags.CreateInstance,
314                         null,
315                         _connector,
316                         new object[] {_appName,
317                                       notificationName,
318                                       id,
319                                       title,
320                                       text,
321                                       res,
322                                       false,
323                                       priority,
324                                       "aaa"},
325                         CultureInfo.InvariantCulture);
326             }
327             else
328             {
329                 n = _connector.GetType("Growl.Connector.Notification").InvokeMember(
330                         "Notification",
331                         BindingFlags.CreateInstance,
332                         null,
333                         _connector,
334                         new object[] {_appName,
335                                       notificationName,
336                                       id,
337                                       title,
338                                       text},
339                         CultureInfo.InvariantCulture);
340             }
341             //_targetConnector.GetType.InvokeMember("Notify", BindingFlags.InvokeMethod, null, _targetConnector, new object[] {n});
342             object cc = _connector.GetType("Growl.Connector.CallbackContext").InvokeMember(
343                 null, BindingFlags.CreateInstance, null, _connector,
344                 new object[] { "some fake information", notificationName },
345                 CultureInfo.InvariantCulture);
346             _targetConnector.GetType().InvokeMember("Notify", BindingFlags.InvokeMethod, null, _targetConnector, new object[] { n, cc }, CultureInfo.InvariantCulture);
347         }
348
349         private void GrowlCallbackHandler(object response, object callbackData, object state)
350         {
351             try
352             {
353                 // 定数取得
354                 object vCLICK =
355                 _core.GetType("Growl.CoreLibrary.CallbackResult").GetField(
356                             "CLICK",
357                            BindingFlags.Public | BindingFlags.Static).GetRawConstantValue();
358                 // 実際の値
359                 object vResult = callbackData.GetType().GetProperty(
360                             "Result",
361                             BindingFlags.Public | BindingFlags.Instance).GetGetMethod().Invoke(callbackData, null);
362                 vResult = (int)vResult;
363                 string notifyId = (string)callbackData.GetType().GetProperty("NotificationID").GetGetMethod().Invoke(callbackData, null);
364                 string notifyName = (string)callbackData.GetType().GetProperty("Type").GetGetMethod().Invoke(callbackData, null);
365                 if (vCLICK.Equals(vResult))
366                 {
367                     NotifyType nt;
368                     switch (notifyName)
369                     {
370                         case "REPLY":
371                             nt = NotifyType.Reply;
372                             break;
373                         case "DIRECT_MESSAGE":
374                             nt = NotifyType.DirectMessage;
375                             break;
376                         case "NOTIFY":
377                             nt = NotifyType.Notify;
378                             break;
379                         case "USERSTREAM_EVENT":
380                             nt = NotifyType.UserStreamEvent;
381                             break;
382                         default:
383                             return;
384                     }
385
386                     NotifyClicked?.Invoke(this, new NotifyCallbackEventArgs(nt, notifyId));
387                 }
388             }
389             catch (Exception)
390             {
391                 return;
392             }
393         }
394     }
395 }