-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRibbon.cs
366 lines (326 loc) · 14.8 KB
/
Ribbon.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using Office = Microsoft.Office.Core;
using Outlook = Microsoft.Office.Interop.Outlook;
using System.Xml;
using Microsoft.Office.Interop.Outlook;
using Microsoft.Office.Tools.Ribbon;
using TypicalReply.Config;
using Microsoft.Office.Core;
using System.Xml.Linq;
using System.Globalization;
using System.Threading;
// TODO: リボン (XML) アイテムを有効にするには、次の手順に従います:
// 1: 次のコード ブロックを ThisAddin、ThisWorkbook、ThisDocument のいずれかのクラスにコピーします。
// protected override Microsoft.Office.Core.IRibbonExtensibility CreateRibbonExtensibilityObject()
// {
// return new Ribbon();
// }
// 2. ボタンのクリックなど、ユーザーの操作を処理するためのコールバック メソッドを、このクラスの
// "リボンのコールバック" 領域に作成します。メモ: このリボンがリボン デザイナーからエクスポートされたものである場合は、
// イベント ハンドラー内のコードをコールバック メソッドに移動し、リボン拡張機能 (RibbonX) のプログラミング モデルで
// 動作するように、コードを変更します。
// 3. リボン XML ファイルのコントロール タグに、コードで適切なコールバック メソッドを識別するための属性を割り当てます。
// 詳細については、Visual Studio Tools for Office ヘルプにあるリボン XML のドキュメントを参照してください。
namespace TypicalReply
{
[ComVisible(true)]
public class Ribbon : IRibbonExtensibility
{
private IRibbonUI ribbon;
public Ribbon()
{
}
#region IRibbonExtensibility のメンバー
public string GetCustomUI(string ribbonID)
{
try
{
if (ribbonID != "Microsoft.Outlook.Mail.Read" && ribbonID != "Microsoft.Outlook.Explorer")
{
return "";
}
Logger.Log("Start to setup custom UI");
string ribbonTemplate = GetResourceText("TypicalReply.Ribbon.xml");
var xmlDocument = new XmlDocument();
xmlDocument.LoadXml(ribbonTemplate);
string namespaceURI = xmlDocument.ChildNodes[1].NamespaceURI;
RuntimeParams global = RuntimeParams.GetInstance();
XmlNode removeTargetNode = null;
if (ribbonID == "Microsoft.Outlook.Mail.Read")
{
// An error "TabMail does not found" can be raised if TabMail is specified
// when target ribbon is not "Microsoft.Outlook.Mail.Read"
removeTargetNode = xmlDocument.SelectSingleNode("//*[@idMso='TabMail']");
}
else if (ribbonID == "Microsoft.Outlook.Explorer")
{
// An error "TabReadMessage does not found" can be raised if TabReadMessage is specified
// when target ribbon is not "Microsoft.Outlook.Mail.Read"
removeTargetNode = xmlDocument.SelectSingleNode("//*[@idMso='TabReadMessage']");
}
removeTargetNode?.ParentNode.RemoveChild(removeTargetNode);
XmlNode groupInTabMailElem = xmlDocument.SelectSingleNode($"//*[@id='{Const.Button.TabMailGroupId}']");
XmlNode groupInTabReadMessageElem = xmlDocument.SelectSingleNode($"//*[@id='{Const.Button.TabReadMessageGroupId}']");
XmlNode contextGalleryElem = xmlDocument.SelectSingleNode($"//*[@id='{Const.Button.ContextMenuGalleryId}']");
var insertMsoTargetParams = new List<(XmlNode, string)>
{
(groupInTabMailElem, global.Config.TabMailInsertAfterMso),
(groupInTabReadMessageElem, global.Config.TabReadInsertAfterMso),
(contextGalleryElem, global.Config.ContextMenuInsertAfterMso),
};
foreach (var (node, insertAfterMso) in insertMsoTargetParams)
{
var nodeAsElement = node as XmlElement;
if (node == null)
{
continue;
}
if (!string.IsNullOrEmpty(insertAfterMso))
{
nodeAsElement.SetAttribute("insertAfterMso", insertAfterMso);
}
}
var targetParams = new List<(XmlNode, string)>
{
(groupInTabMailElem, Const.Button.TabMailGroupId),
(groupInTabReadMessageElem, Const.Button.TabReadMessageGroupId),
(contextGalleryElem, Const.Button.ContextMenuGalleryId),
};
foreach (var buttonConfig in global.Config.ButtonConfigList)
{
if (string.IsNullOrEmpty(buttonConfig.Id))
{
continue;
}
if (string.IsNullOrEmpty(buttonConfig.Label))
{
continue;
}
foreach (var (node, suffix) in targetParams)
{
if (node == null)
{
continue;
}
XmlElement button = xmlDocument.CreateElement("button", namespaceURI);
button.SetAttribute("id", $"{buttonConfig.Id}{suffix}");
button.SetAttribute("label", buttonConfig.Label);
button.SetAttribute("onAction", nameof(OnClickButton));
if (suffix != Const.Button.ContextMenuGalleryId)
{
//We cannot specify button size in the context menu.
switch (buttonConfig.Size)
{
case ButtonSize.Large:
button.SetAttribute("size", "large");
break;
case ButtonSize.Normal:
button.SetAttribute("size", "normal");
break;
}
}
if (!string.IsNullOrEmpty(buttonConfig.Image))
{
button.SetAttribute("image", buttonConfig.Image);
}
//if (!string.IsNullOrEmpty(templateConfig.AccessKey))
//{
// button.SetAttribute("keytip", templateConfig.AccessKey);
//}
node.AppendChild(button);
}
}
Logger.Log("Finish to setup custom UI");
return xmlDocument.InnerXml;
}
catch (System.Exception ex)
{
Logger.Log(ex);
throw;
}
}
#endregion
#region リボンのコールバック
//ここでコールバック メソッドを作成します。コールバック メソッドの追加について詳しくは https://go.microsoft.com/fwlink/?LinkID=271226 をご覧ください
public void Ribbon_Load(IRibbonUI ribbonUI)
{
this.ribbon = ribbonUI;
}
public virtual object Ribbon_LoadImage(string imageName)
{
switch (imageName)
{
case "logo.png":
return Properties.Resources.logo;
}
return null;
}
#endregion
private MailItem GetActiveExplorerMailItem()
{
Explorer activeExplorer = Globals.ThisAddIn.Application.ActiveExplorer();
if (activeExplorer.Selection.Count > 0 &&
activeExplorer.Selection[1] is MailItem selObject)
{
return selObject;
}
return null;
}
private MailItem GetActiveInspectorMailItem()
{
return Globals.ThisAddIn.Application.ActiveInspector()?.CurrentItem as MailItem;
}
private MailItem CreateReplyMail(ButtonConfig config, MailItem selectedMailItem)
{
MailItem mailItemToReply = null;
switch (config.RecipientsType)
{
case RecipientsType.All:
mailItemToReply = selectedMailItem.ReplyAll();
break;
case RecipientsType.Sender:
mailItemToReply = selectedMailItem.Reply();
break;
case RecipientsType.SpecifiedByUser:
mailItemToReply = selectedMailItem.Reply();
while (mailItemToReply.Recipients.Count > 0)
{
mailItemToReply.Recipients.Remove(1);
}
foreach (var recipient in config.Recipients)
{
mailItemToReply.Recipients.Add(recipient);
}
break;
default:
mailItemToReply = selectedMailItem.Reply();
while (mailItemToReply.Recipients.Count > 0)
{
mailItemToReply.Recipients.Remove(1);
}
break;
}
if (config.AllowedDomainsType == AllowedDomainsType.SpecifiedByUser)
{
var loweredAllowedDomains = config.LoweredAllowedDomains;
foreach (Recipient recipient in mailItemToReply.Recipients)
{
RecipientInfo recipientInfo = new RecipientInfo(recipient);
string targetDomain = recipientInfo.Domain.ToLowerInvariant();
if (loweredAllowedDomains.Any(_ => _ == targetDomain))
{
continue;
}
Logger.Log($"Prohibited domain: {targetDomain}");
Marshal.ReleaseComObject(mailItemToReply);
return null;
}
}
if (!string.IsNullOrEmpty(config.Subject))
{
mailItemToReply.Subject = config.Subject;
}
if (!string.IsNullOrEmpty(config.SubjectPrefix))
{
mailItemToReply.Subject = $"{config.SubjectPrefix} {mailItemToReply.Subject}";
}
string replyMessage = "";
if (config.QuoteType && !string.IsNullOrEmpty(selectedMailItem.Body))
{
switch (mailItemToReply.BodyFormat)
{
case OlBodyFormat.olFormatHTML:
case OlBodyFormat.olFormatRichText:
mailItemToReply.BodyFormat = OlBodyFormat.olFormatPlain;
replyMessage = "\n\n> -----Original Message-----\n";
replyMessage += string.Join("\n", mailItemToReply.Body.TrimStart().Split('\n').Select(_ => $"> {_}"));
break;
default:
replyMessage = mailItemToReply.Body;
break;
}
}
mailItemToReply.Body = config.Body ?? "";
if (!string.IsNullOrEmpty(replyMessage))
{
mailItemToReply.Body += replyMessage;
}
switch (config.ForwardType)
{
case ForwardType.Attachment:
mailItemToReply.Attachments.Add(selectedMailItem, OlAttachmentType.olEmbeddeditem);
break;
case ForwardType.Inline:
//TODO: Support Inline
mailItemToReply.Attachments.Add(selectedMailItem, OlAttachmentType.olEmbeddeditem);
break;
}
return mailItemToReply;
}
public void OnClickButton(IRibbonControl control)
{
string id = control.Id;
ButtonConfig config = RuntimeParams.
GetInstance().
Config.
ButtonConfigList?.
FirstOrDefault(_ =>
id == $"{_.Id}{Const.Button.TabMailGroupId}" ||
id == $"{_.Id}{Const.Button.ContextMenuGalleryId}" ||
id == $"{_.Id}{Const.Button.TabReadMessageGroupId}");
if (config is null)
{
Logger.Log("Failed to get the target button config");
return;
}
MailItem selectedMailItem;
if (control.Id == $"{config.Id}{Const.Button.TabReadMessageGroupId}")
{
selectedMailItem = GetActiveInspectorMailItem();
}
else
{
selectedMailItem = GetActiveExplorerMailItem();
}
if (selectedMailItem is null)
{
Logger.Log("No MailItem found");
return;
}
MailItem replyMail = CreateReplyMail(config, selectedMailItem);
replyMail?.Display();
}
public string GetLabel(IRibbonControl control)
{
Config.Config typicalReplyConfig = RuntimeParams.GetInstance().Config;
return typicalReplyConfig.GroupLabel;
}
#region ヘルパー
private static string GetResourceText(string resourceName)
{
Assembly asm = Assembly.GetExecutingAssembly();
string[] resourceNames = asm.GetManifestResourceNames();
for (int i = 0; i < resourceNames.Length; ++i)
{
if (string.Compare(resourceName, resourceNames[i], StringComparison.OrdinalIgnoreCase) == 0)
{
using (StreamReader resourceReader = new StreamReader(asm.GetManifestResourceStream(resourceNames[i])))
{
if (resourceReader != null)
{
return resourceReader.ReadToEnd();
}
}
}
}
return null;
}
#endregion
}
}