OSDN Git Service

プロフィール画面へのD&Dによるアイコン変更時に確認ダイアログを表示するように変更
[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
39 namespace OpenTween
40 {
41     public class GrowlHelper
42     {
43         private Assembly _connector = null;
44         private Assembly _core = null;
45
46         private object _growlNTreply;
47         private object _growlNTdm;
48         private object _growlNTnew;
49         private object _growlNTusevent;
50         private object _growlApp;
51
52         private object _targetConnector;
53
54         private string _appName = "";
55         bool _initialized = false;
56
57         public class NotifyCallbackEventArgs : EventArgs
58         {
59             public long StatusId { get; set; }
60             public NotifyType NotifyType { get; set; }
61             public NotifyCallbackEventArgs(NotifyType notifyType, string statusId)
62             {
63                 if (statusId.Length > 1)
64                 {
65                     this.StatusId = long.Parse(statusId);
66                     this.NotifyType = notifyType;
67                 }
68             }
69         }
70
71         public event EventHandler<NotifyCallbackEventArgs> NotifyClicked;
72
73         public string AppName
74         {
75             get { return _appName; }
76         }
77
78         public enum NotifyType
79         {
80             Reply = 0,
81             DirectMessage = 1,
82             Notify = 2,
83             UserStreamEvent = 3,
84         }
85
86         public GrowlHelper(string appName)
87         {
88             _appName = appName;
89         }
90
91         public bool IsAvailable
92         {
93             get
94             {
95                 if (_connector == null || _core == null || !_initialized)
96                     return false;
97                 else
98                     return true;
99             }
100         }
101
102         private byte[] IconToByteArray(string filename)
103         {
104             using (Icon ic = new Icon(filename))
105             {
106                 return IconToByteArray(ic);
107             }
108         }
109
110         private byte[] IconToByteArray(Icon icondata)
111         {
112             using (MemoryStream ms = new MemoryStream())
113             {
114                 using (Icon ic = new Icon(icondata, 48, 48))
115                 {
116                     ic.ToBitmap().Save(ms, ImageFormat.Png);
117                     return ms.ToArray();
118                 }
119             }
120         }
121
122         public static bool IsDllExists
123         {
124             get
125             {
126                 string dir = Application.StartupPath;
127                 string connectorPath = Path.Combine(dir, "Growl.Connector.dll");
128                 string corePath = Path.Combine(dir, "Growl.CoreLibrary.dll");
129                 if (File.Exists(connectorPath) && File.Exists(corePath))
130                     return true;
131                 else
132                     return false;
133             }
134         }
135
136         public bool RegisterGrowl()
137         {
138             _initialized = false;
139             string dir = Application.StartupPath;
140             string connectorPath = Path.Combine(dir, "Growl.Connector.dll");
141             string corePath = Path.Combine(dir, "Growl.CoreLibrary.dll");
142
143             try
144             {
145                 if (!IsDllExists) return false;
146                 _connector = Assembly.LoadFile(connectorPath);
147                 _core = Assembly.LoadFile(corePath);
148             }
149             catch (Exception)
150             {
151                 return false;
152             }
153
154             try
155             {
156                 _targetConnector = _connector.CreateInstance("Growl.Connector.GrowlConnector");
157                 Type _t = _connector.GetType("Growl.Connector.NotificationType");
158
159                 _growlNTreply = _t.InvokeMember(null,
160                     BindingFlags.CreateInstance, null, null, new object[] { "REPLY", "Reply" });
161
162                 _growlNTdm = _t.InvokeMember(null,
163                     BindingFlags.CreateInstance, null, null, new object[] { "DIRECT_MESSAGE", "DirectMessage" });
164
165                 _growlNTnew = _t.InvokeMember(null,
166                     BindingFlags.CreateInstance, null, null, new object[] { "NOTIFY", "新着通知" });
167
168                 _growlNTusevent = _t.InvokeMember(null,
169                     BindingFlags.CreateInstance, null, null, new object[] { "USERSTREAM_EVENT", "UserStream Event" });
170
171                 object encryptType =
172                         _connector.GetType("Growl.Connector.Cryptography+SymmetricAlgorithmType").InvokeMember(
173                             "PlainText", BindingFlags.GetField, null, null, null);
174                 _targetConnector.GetType().InvokeMember("EncryptionAlgorithm", BindingFlags.SetProperty, null, _targetConnector, new object[] { encryptType });
175
176                 _growlApp = _connector.CreateInstance(
177                     "Growl.Connector.Application", false, BindingFlags.Default, null, new object[] { _appName }, null, null);
178
179
180                 if (File.Exists(Path.Combine(Application.StartupPath, "Icons\\Tween.png")))
181                 {
182                     // Icons\Tween.pngを使用
183                     ConstructorInfo ci = _core.GetType(
184                         "Growl.CoreLibrary.Resource").GetConstructor(
185                         BindingFlags.NonPublic | BindingFlags.Instance,
186                         null, new Type[] { typeof(string) }, null);
187
188                     object data = ci.Invoke(new object[] { Path.Combine(Application.StartupPath, "Icons\\Tween.png") });
189                     PropertyInfo pi = _growlApp.GetType().GetProperty("Icon");
190                     pi.SetValue(_growlApp, data, null);
191
192                 }
193                 else if (File.Exists(Path.Combine(Application.StartupPath, "Icons\\MIcon.ico")))
194                 {
195                     // アイコンセットにMIcon.icoが存在する場合それを使用
196                     ConstructorInfo cibd = _core.GetType(
197                         "Growl.CoreLibrary.BinaryData").GetConstructor(
198                         BindingFlags.Public | BindingFlags.Instance,
199                         null, new Type[] { typeof(byte[]) }, null);
200                     object bdata = cibd.Invoke(
201                         new object[] { IconToByteArray(Path.Combine(Application.StartupPath, "Icons\\MIcon.ico")) });
202
203                     ConstructorInfo ciRes = _core.GetType(
204                         "Growl.CoreLibrary.Resource").GetConstructor(
205                         BindingFlags.NonPublic | BindingFlags.Instance,
206                         null, new Type[] { bdata.GetType() }, null);
207
208                     object data = ciRes.Invoke(new object[] { bdata });
209                     PropertyInfo pi = _growlApp.GetType().GetProperty("Icon");
210                     pi.SetValue(_growlApp, data, null);
211                 }
212                 else
213                 {
214                     //内蔵アイコンリソースを使用
215                     ConstructorInfo cibd = _core.GetType(
216                         "Growl.CoreLibrary.BinaryData").GetConstructor(
217                         BindingFlags.Public | BindingFlags.Instance,
218                         null, new Type[] { typeof(byte[]) }, null);
219                     object bdata = cibd.Invoke(
220                         new object[] { IconToByteArray(Properties.Resources.MIcon) });
221
222                     ConstructorInfo ciRes = _core.GetType(
223                         "Growl.CoreLibrary.Resource").GetConstructor(
224                         BindingFlags.NonPublic | BindingFlags.Instance,
225                         null, new Type[] { bdata.GetType() }, null);
226
227                     object data = ciRes.Invoke(new object[] { bdata });
228                     PropertyInfo pi = _growlApp.GetType().GetProperty("Icon");
229                     pi.SetValue(_growlApp, data, null);
230                 }
231
232                 MethodInfo mi = _targetConnector.GetType().GetMethod("Register", new Type[] { _growlApp.GetType(), _connector.GetType("Growl.Connector.NotificationType[]") });
233
234                 _t = _connector.GetType("Growl.Connector.NotificationType");
235
236                 ArrayList arglist = new ArrayList();
237                 arglist.Add(_growlNTreply);
238                 arglist.Add(_growlNTdm);
239                 arglist.Add(_growlNTnew);
240                 arglist.Add(_growlNTusevent);
241
242                 mi.Invoke(_targetConnector, new object[] { _growlApp, arglist.ToArray(_t) });
243
244                 // コールバックメソッドの登録
245                 Type tGrowlConnector = _connector.GetType("Growl.Connector.GrowlConnector");
246                 EventInfo evNotificationCallback = tGrowlConnector.GetEvent("NotificationCallback");
247                 Type tDelegate = evNotificationCallback.EventHandlerType;
248                 MethodInfo miHandler = typeof(GrowlHelper).GetMethod("GrowlCallbackHandler", BindingFlags.NonPublic | BindingFlags.Instance);
249                 Delegate d = Delegate.CreateDelegate(tDelegate, this, miHandler);
250                 MethodInfo miAddHandler = evNotificationCallback.GetAddMethod();
251                 object[] addHandlerArgs = { d };
252                 miAddHandler.Invoke(_targetConnector, addHandlerArgs);
253
254                 _initialized = true;
255             }
256             catch (Exception)
257             {
258                 _initialized = false;
259                 return false;
260             }
261
262             return true;
263         }
264
265         public void Notify(NotifyType notificationType, string id, string title, string text, Image icon = null, string url = "")
266         {
267             if (!_initialized) return;
268             string notificationName = "";
269             switch (notificationType)
270             {
271                 case NotifyType.Reply:
272                     notificationName = "REPLY";
273                     break;
274                 case NotifyType.DirectMessage:
275                     notificationName = "DIRECT_MESSAGE";
276                     break;
277                 case NotifyType.Notify:
278                     notificationName = "NOTIFY";
279                     break;
280                 case NotifyType.UserStreamEvent:
281                     notificationName = "USERSTREAM_EVENT";
282                     break;
283             }
284             object n = null;
285             if (icon != null || !string.IsNullOrEmpty(url))
286             {
287                 Type gCore = _core.GetType("Growl.CoreLibrary.Resource");
288                 object res = null;
289                 if (icon != null)
290                 {
291                     res = gCore.InvokeMember("op_Implicit",
292                                              BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod,
293                                              null,
294                                              null,
295                                              new object[] { icon });
296                 }
297                 else
298                 {
299                     res = gCore.InvokeMember("op_Implicit",
300                                              BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod,
301                                              null,
302                                              null,
303                                              new object[] { url });
304                 }
305                 object priority =
306                         _connector.GetType("Growl.Connector.Priority").InvokeMember(
307                             "Normal", BindingFlags.GetField, null, null, null);
308                 n = _connector.GetType("Growl.Connector.Notification").InvokeMember(
309                         "Notification",
310                         BindingFlags.CreateInstance,
311                         null,
312                         _connector,
313                         new object[] {_appName,
314                                       notificationName,
315                                       id,
316                                       title,
317                                       text,
318                                       res,
319                                       false,
320                                       priority,
321                                       "aaa"});
322             }
323             else
324             {
325                 n = _connector.GetType("Growl.Connector.Notification").InvokeMember(
326                         "Notification",
327                         BindingFlags.CreateInstance,
328                         null,
329                         _connector,
330                         new object[] {_appName,
331                                       notificationName,
332                                       id,
333                                       title,
334                                       text});
335             }
336             //_targetConnector.GetType.InvokeMember("Notify", BindingFlags.InvokeMethod, null, _targetConnector, new object[] {n});
337             object cc = _connector.GetType("Growl.Connector.CallbackContext").InvokeMember(
338                 null, BindingFlags.CreateInstance, null, _connector,
339                 new object[] { "some fake information", notificationName });
340             _targetConnector.GetType().InvokeMember("Notify", BindingFlags.InvokeMethod, null, _targetConnector, new object[] { n, cc });
341         }
342
343         private void GrowlCallbackHandler(object response, object callbackData, object state)
344         {
345             try
346             {
347                 // 定数取得
348                 object vCLICK =
349                 _core.GetType("Growl.CoreLibrary.CallbackResult").GetField(
350                             "CLICK",
351                            BindingFlags.Public | BindingFlags.Static).GetRawConstantValue();
352                 // 実際の値
353                 object vResult = callbackData.GetType().GetProperty(
354                             "Result",
355                             BindingFlags.Public | BindingFlags.Instance).GetGetMethod().Invoke(callbackData, null);
356                 vResult = (int)vResult;
357                 string notifyId = (string)callbackData.GetType().GetProperty("NotificationID").GetGetMethod().Invoke(callbackData, null);
358                 string notifyName = (string)callbackData.GetType().GetProperty("Type").GetGetMethod().Invoke(callbackData, null);
359                 if (vCLICK.Equals(vResult))
360                 {
361                     NotifyType nt;
362                     switch (notifyName)
363                     {
364                         case "REPLY":
365                             nt = NotifyType.Reply;
366                             break;
367                         case "DIRECT_MESSAGE":
368                             nt = NotifyType.DirectMessage;
369                             break;
370                         case "NOTIFY":
371                             nt = NotifyType.Notify;
372                             break;
373                         case "USERSTREAM_EVENT":
374                             nt = NotifyType.UserStreamEvent;
375                             break;
376                         default:
377                             return;
378                     }
379
380                     if (NotifyClicked != null)
381                         NotifyClicked(this, new NotifyCallbackEventArgs(nt, notifyId));
382                 }
383             }
384             catch (Exception)
385             {
386                 return;
387             }
388         }
389     }
390 }