5 // Created by kuri on 10/02/01.
6 // Copyright 2010-2017 kuri. All rights reserved.
8 #import <objc/runtime.h>
9 #import <objc/objc-runtime.h>
10 #import <WebKit/WebKit.h>
14 static NSMutableArray *khash;
15 static NSMutableArray *check_at_save;
17 static NSString *roman[] = {@"I", @"II", @"III", @"IV", @"V", @"VI", @"VII", @"VIII", @"IX", @"X"};
18 static NSString *dep[] = {@"ミリ", @"キロ", @"センチ", @"メートル", @"グラム", @"トン", @"アール", @"ヘクタール",
19 @"リットル", @"ワット", @"カロリー", @"ドル", @"セント", @"パーセント", @"ミリバール", @"ページ",
20 @"mm", @"cm", @"km", @"mg", @"kg", @"cc", @"明治", @"大正", @"昭和", @"平成", @"No.", @"K.K.", @"TEL",
21 @"(上)", @"(中)", @"(下)", @"(左)", @"(右)", @"(株)", @"(有)", @"(代)", @"Σ"};
22 static NSString *dayOfWeek = @"㈰㈪㈫㈬㈭㈮㈯㉀㈷㉂㉃㈹㈺㈱㈾㈴㈲㈻㈶㈳㈵㈼㈽㈿㈸";
23 static NSString *subOfDayOfWeek[] = {@"(日)",@"(月)",@"(火)",@"(水)",@"(木)",@"(金)",@"(土)",@"(祭)",@"(祝)",@"(自)",
24 @"(至)",@"(代)",@"(呼)",@"(株)",@"(資)",@"(名)",@"(有)",@"(学)",@"(財)",@"(社)",
25 @"(特)",@"(監)",@"(企)",@"(協)",@"(労)"};
26 static NSString *circledNumbers = @"①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳ⅠⅡⅢⅣⅤ";
27 static NSString *subOfCircledNum[] = {@"(1)",@"(2)",@"(3)",@"(4)",@"(5)",@"(6)",@"(7)",@"(8)",@"(9)",@"(10)",
28 @"(11)",@"(12)",@"(13)",@"(14)",@"(15)",@"(16)",@"(17)",@"(18)",@"(19)",@"(20)",
29 @"I",@"II",@"III",@"IV",@"V"};
30 static NSString *symbols = @"㍉㌔㌢㍍㌘㌧㌃㌶㍑㍗㌍㌦㌣㌫㍊㌻㎜㎝㎞㎎㎏㏄㍾㍽㍼㍻№㏍℡㊤㊥㊦㊧㊨㈱㈲㈹∑";
32 static unsigned long long LF_Encoding_ISO2022JP = NSISO2022JPStringEncoding;
33 static unsigned long long LF_Encoding_Auto = 0;
35 void swizzlingMethod(Class aClass, SEL aSelector, SEL nSelector, IMP nImplement) {
36 Method orig_method, alt_method;
38 if ((orig_method = class_getInstanceMethod(aClass, aSelector)) == NULL) {
39 NSLog(@"Swizzling Method: Original Method is not found. [%@ %@]", NSStringFromClass(aClass), NSStringFromSelector(aSelector));
40 return; // Original Method is not found.
42 // If orig_method was the superclass's instance method, so now we'll add the implement as method of self class.
43 if (class_addMethod(aClass, aSelector, method_getImplementation(orig_method), method_getTypeEncoding(orig_method)) == YES) {
44 orig_method = class_getInstanceMethod(aClass, aSelector);
46 if (class_addMethod(aClass, nSelector, nImplement, method_getTypeEncoding(orig_method)) == NO) {
47 NSLog(@"Swizzling Method: Can't add new method.");
48 return; // Can't add new method
50 alt_method = class_getInstanceMethod(aClass, nSelector);
51 method_exchangeImplementations(orig_method, alt_method);
52 //NSLog(@"Swizzling Method: Success.");
55 static void backendSetPreferredEncoding(id backend, unsigned long long encoding)
57 if ([app ver] == LF_Mavericks) {
58 Ivar ivar = object_getInstanceVariable(backend, "_flags", NULL);
59 _LF_flags *_flags = (_LF_flags *)((char *)backend + ivar_getOffset(ivar));
60 _flags->encodingHint = encoding;
61 } else if ([app ver] == LF_Yosemite || [app ver] == LF_ElCapitan ||
62 [app ver] == LF_Sierra || [app ver] == LF_HighSierra ||
63 [app ver] == LF_Mojave) {
64 [backend setEncodingHint: encoding];
68 static unsigned long long backendGetPreferredEncoding(id backend)
70 if ([app ver] == LF_Mavericks) {
71 Ivar ivar = object_getInstanceVariable(backend, "_flags", NULL);
72 _LF_flags *_flags = (_LF_flags *)((char *)backend + ivar_getOffset(ivar));
73 return _flags->encodingHint; //FIXME: [backend _encodingHint] return wrong value?
74 } else if ([app ver] == LF_Yosemite || [app ver] == LF_ElCapitan ||
75 [app ver] == LF_Sierra || [app ver] == LF_HighSierra ||
76 [app ver] == LF_Mojave) {
77 return [backend encodingHint];
79 return LF_Encoding_Auto;
82 int fixTextNode(DOMText *node, DOMRange *range, BOOL isCheck, BOOL isOpen)
89 if ([node nodeType] != DOM_TEXT_NODE) return 0;
92 if ([node isEqualNode:[range startContainer]]) {
93 c_start = [range startOffset];
95 if ([node isEqualNode:[range endContainer]]) {
96 c_end = [range endOffset];
99 // 誤ったUnicodeテーブルが用いられている文字を本来の文字に置換
100 for (i = 0; i < [[node data] length]; i++) {
101 switch ([[node data] characterAtIndex:i]) {
103 [node replaceData:i length:1 data:@"—"]; // U+2014
106 [node replaceData:i length:1 data:@"〜"]; // U+301c
109 [node replaceData:i length:1 data:@"‖"]; // U+2016
112 [node replaceData:i length:1 data:@"−"]; // U+2212
115 [node replaceData:i length:1 data:@"¢"]; // U+00a2
118 [node replaceData:i length:1 data:@"£"]; // U+00a3
121 [node replaceData:i length:1 data:@"¬"]; // U+00ac
126 for (i = 0; i < [[node data] length]; i++) {
127 NSString *us = [[node data] substringWithRange:NSMakeRange(i, 1)];
128 unichar uc = [us characterAtIndex:0];
131 if ([us canBeConvertedToEncoding:NSISO2022JPStringEncoding] != YES && uc != 0xa0) {
133 if (isOpen) { // 編集開始時
134 if ([app isOsDependentFix] == YES) {
135 if ((loc = [dayOfWeek rangeOfString:us].location) != NSNotFound) {
136 if ([app parenSymbolFix] == YES) {
137 if (((loc == 11)||(loc == 13)||(loc == 16)) &&
138 ([app someParenSymbolNotFix] == YES)) {
139 ns = subOfDayOfWeek[loc];
141 ns = subOfCircledNum[loc];
144 ns = subOfDayOfWeek[loc];
146 } else { // (SnowLeopard or Lion) OR (not DayOfWeek)
147 if ((0x2460 <= uc) && (uc <= 0x2473)) { // ①〜⑳ -> (1)〜(20)
148 ns = subOfCircledNum[uc-0x2460];
149 } else if ((0x2160 <= uc && uc <= 0x2169) && ([app isOsDependentFix]==YES)) {// Ⅰ〜Ⅹ -> I〜X
150 ns = roman[uc-0x2160];
151 } else if (((loc = [symbols rangeOfString:us].location) != NSNotFound)
155 if ([app isAllLetterFix] == YES) {
157 } else { // [app isAllLetterFix] == NO
162 } else { // [app isOsDependentFix] == NO
163 if ([app isAllLetterFix] == YES) {
165 } else { // [app isAllLetterFix] == NO
170 if ([app isOsDependentFix] == YES) {
171 if ((0x2460 <= uc) && (uc <= 0x2473)) { // ①〜⑳ -> (1)〜(20)
172 ns = subOfCircledNum[uc-0x2460];
173 } else if ((0x2160 <= uc && uc <= 0x2169) && ([app isOsDependentFix]==YES)) {// Ⅰ〜Ⅹ -> I〜X
174 ns = roman[uc-0x2160];
175 } else if ((loc = [symbols rangeOfString:us].location) != NSNotFound) {
177 } else if ((loc = [dayOfWeek rangeOfString:us].location) != NSNotFound) {
178 ns = subOfDayOfWeek[loc];
180 if ([app isAllLetterFix] == YES) {
182 } else { // [app isAllLetterFix] == NO
186 } else { // [app isOsDependentFix] == NO
187 if ([app isAllLetterFix] == YES) {
189 } else { // [app isAllLetterFix] == NO
195 if ((c_start != -1) && (i < c_start)) {
196 c_start += [ns length] - 1;
198 if ((c_end != -1) && (i < c_end)) {
199 c_end += [ns length] - 1;
202 [node replaceData:i length:1 data:ns];
203 i += [ns length] - 1;
208 if ((c_start != -1) && 0 < replaced) {
209 [range setStart:node offset:c_start];
211 if ((c_end != -1) && 0 < replaced) {
212 [range setEnd:node offset:c_end];
218 int fixReflexively(DOMNode *node, DOMRange *range, BOOL isCheck, BOOL isOpen)
223 if ([node hasChildNodes]) {
224 for (n = [node firstChild]; n != NULL; n = [n nextSibling]) {
225 replaced += fixReflexively(n, range, isCheck, isOpen); // 再帰的にノードをたどる
228 if ([node nodeType] == DOM_TEXT_NODE) {
229 replaced = fixTextNode((DOMText*)node, range, isCheck, isOpen);
235 int fixLetter(id self, id composeView, BOOL isCheck, BOOL isOpen)
240 WebFrame *frame = [(WebView *)composeView mainFrame];
241 DOMDocument *dom = [frame DOMDocument];
242 DOMElement *root = [dom documentElement];
243 DOMNodeList *nodelist = [root getElementsByTagName:@"body"];
245 if ([nodelist length] != 1) return -1;
247 DOMNode *body = [nodelist item:0];
248 DOMRange *range = [composeView selectedDOMRange];
250 replaced = fixReflexively(body, range, isCheck, isOpen);
252 if (0 < replaced && !isCheck) {
253 [composeView setSelectedDOMRange:range affinity:NSSelectionAffinityUpstream];
256 @catch (NSException * e) {
257 NSLog(@"LetterFix: caught %@ %@", [e name], [e reason]);
263 BOOL checkSubject(id self)
265 NSMutableString *substr = [NSMutableString stringWithString:[[self backEnd] subject]];
268 for (i = 0; i < [substr length]; i++) {
269 NSString *us = [substr substringWithRange:NSMakeRange(i, 1)];
270 unichar uc = [us characterAtIndex:0];
281 if ([us canBeConvertedToEncoding:NSISO2022JPStringEncoding] != YES) return TRUE;
289 BOOL checkSubjectOnLoad(id self)
291 NSMutableString *substr = [NSMutableString stringWithString:[[self backEnd] subject]];
294 for (i = 0; i < [substr length]; i++) {
295 NSString *us = [substr substringWithRange:NSMakeRange(i, 1)];
296 if ([us canBeConvertedToEncoding:NSISO2022JPStringEncoding] != YES) {
297 if (([app isOsDependentFix] == YES) && ([app parenSymbolFix] == YES) &&
298 ((loc = [dayOfWeek rangeOfString:us].location) != NSNotFound) &&
299 ([app someParenSymbolNotFix] == NO || (loc != 11 && loc != 13 && loc != 16))) {
307 void fixSubjectOnLoad(id self)
309 NSMutableString *substr = [NSMutableString stringWithString:[[self backEnd] subject]];
312 for (i = 0; i < [substr length]; i++) {
313 NSString *us = [substr substringWithRange:NSMakeRange(i, 1)];
314 unichar uc = [us characterAtIndex:0];
319 [substr replaceCharactersInRange:NSMakeRange(i, 1) withString:@"—"];
322 [substr replaceCharactersInRange:NSMakeRange(i, 1) withString:@"〜"];
325 [substr replaceCharactersInRange:NSMakeRange(i, 1) withString:@"−"];
328 [substr replaceCharactersInRange:NSMakeRange(i, 1) withString:@"‖"];
331 [substr replaceCharactersInRange:NSMakeRange(i, 1) withString:@"¢"];
334 [substr replaceCharactersInRange:NSMakeRange(i, 1) withString:@"£"];
337 [substr replaceCharactersInRange:NSMakeRange(i, 1) withString:@"¬"];
340 if ([us canBeConvertedToEncoding:NSISO2022JPStringEncoding] != YES) {
341 if (([app isOsDependentFix] == YES) && ([app parenSymbolFix] == YES) &&
342 ((loc = [dayOfWeek rangeOfString:us].location) != NSNotFound) &&
343 ([app someParenSymbolNotFix] == NO || (loc != 11 && loc != 13 && loc != 16))) {
344 [substr replaceCharactersInRange:NSMakeRange(i, 1)
345 withString:[circledNumbers substringWithRange:NSMakeRange(loc, 1)]];
351 [[(LetterFix *)self backEnd] setSubject:substr];
352 [[self _windowLF] setTitle:substr];
354 id headers = [self headersEditor];
355 NSTextField *subjectField = nil;
356 object_getInstanceVariable(headers, "_subjectField", (void **)&subjectField);
357 if (subjectField != nil)
358 [subjectField setStringValue:substr];
361 void fixHeader(id self)
363 NSMutableString *substr = [NSMutableString stringWithString:[[self backEnd] subject]];
366 for (i = 0; i < [substr length]; i++) {
367 NSString *us = [substr substringWithRange:NSMakeRange(i, 1)];
368 unichar uc = [us characterAtIndex:0];
374 [substr replaceCharactersInRange:NSMakeRange(i, 1) withString:@"—"];
377 [substr replaceCharactersInRange:NSMakeRange(i, 1) withString:@"〜"];
380 [substr replaceCharactersInRange:NSMakeRange(i, 1) withString:@"−"];
383 [substr replaceCharactersInRange:NSMakeRange(i, 1) withString:@"‖"];
386 [substr replaceCharactersInRange:NSMakeRange(i, 1) withString:@"¢"];
389 [substr replaceCharactersInRange:NSMakeRange(i, 1) withString:@"£"];
392 [substr replaceCharactersInRange:NSMakeRange(i, 1) withString:@"¬"];
395 if ([us canBeConvertedToEncoding:NSISO2022JPStringEncoding] != YES) {
396 if ((0x2460 <= uc && uc <= 0x2473) && ([app isOsDependentFix]==YES)) { // ①〜⑳ -> (1)〜(20)
397 ns = subOfCircledNum[uc-0x2460];
398 } else if ((0x2160 <= uc && uc <= 0x2169) && ([app isOsDependentFix]==YES)) {// Ⅰ〜Ⅹ -> I〜X
399 ns = roman[uc-0x2160];
400 } else if (((loc = [symbols rangeOfString:us].location) != NSNotFound)
401 && ([app isOsDependentFix]==YES)) {
406 [substr replaceCharactersInRange:NSMakeRange(i, 1) withString:ns];
407 if (1 < [ns length]) {
408 i += [ns length] - 1;
414 [[(LetterFix *)self backEnd] setSubject:substr];
415 [[self _windowLF] setTitle:substr];
417 id headers = [self headersEditor];
418 NSTextField *subjectField = nil;
419 object_getInstanceVariable(headers, "_subjectField", (void **)&subjectField);
420 if (subjectField != nil)
421 [subjectField setStringValue:substr];
424 BOOL _LF_IMP_isLoaded(id self, SEL _cmd)
426 BOOL result = [self _LF_isLoaded]; // call swizzled(original) method
427 if ([app isActive] == NO) {
431 [khash removeObject:self];
434 if ([khash containsObject:self] == YES) return result;
437 id composeView = [self webView];
438 if ((composeView==NULL) || ([(WebView *)composeView isLoading]==YES) || ([(WebView *)composeView isEditable]==NO)) {
439 //[self performSelector:@selector(isLoaded) withObject:nil afterDelay:2];
443 //id backend = [self backEnd];
444 //backendSetPreferredEncoding(backend, LF_Encoding_ISO2022JP);
445 [khash addObject:self];
447 switch ([self messageType]) {
456 case 14:// 添付ファイルとして返信
459 NSLog(@"Unknown MessageType: %d", [self messageType]);
463 if (0 < fixLetter(self, [self webView], TRUE, TRUE) || checkSubjectOnLoad(self)) {
464 if ([app operationAtOpen] == 0) {
465 NSAlert *alert = [[[NSAlert alloc] init] autorelease];
466 [alert addButtonWithTitle:@"変換"];
467 NSButton *button = [alert addButtonWithTitle:@"変換しない"];
468 button.keyEquivalent = @"\x1b";
469 [alert setShowsSuppressionButton:TRUE];
470 [alert setMessageText:@"編集前にメッセージを変換しますか?"];
471 [alert setInformativeText:@"このメッセージには ISO 2022-JP でエンコードできない文字が含まれています。"];
472 [alert setAlertStyle:NSInformationalAlertStyle];
473 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.8 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
474 [alert beginSheetModalForWindow:[self _windowLF] completionHandler:^(NSModalResponse returnCode){
475 if (returnCode == NSAlertFirstButtonReturn) {
476 fixSubjectOnLoad(self);
477 if ([app ver] == LF_Mavericks || [app ver] == LF_Yosemite) {
478 fixLetter(self, [self webView], FALSE, TRUE);
479 } else if ([app ver] == LF_ElCapitan || [app ver] == LF_Sierra ||
480 [app ver] == LF_HighSierra|| [app ver] == LF_Mojave) {
481 fixLetter(self, [self composeWebView], FALSE, TRUE);
483 } else if (returnCode == NSAlertSecondButtonReturn) {
485 if ([[alert suppressionButton] state] == NSOnState) {
486 if (returnCode == NSAlertFirstButtonReturn) {
487 [app setOperationAtOpen:1];
488 } else if (returnCode == NSAlertSecondButtonReturn) {
489 [app setOperationAtOpen:2];
494 } else if ([app operationAtOpen] == 1) {
495 fixSubjectOnLoad(self);
496 fixLetter(self, [self webView], FALSE, TRUE);
497 [[self backEnd] setHasChanges:FALSE];
501 @catch (NSException * exception) {
502 NSLog(@"LetterFix: caught %@ %@", [exception name], [exception reason]);
508 void _LF_IMP_finishLoadingEditor(id self, SEL _cmd)
510 [self _LF_finishLoadingEditor];
512 if ([app isActive] == NO) {
517 id composeView = [self composeWebView];
518 if ((composeView==NULL) || ([(WebView *)composeView isLoading]==YES) || ([(WebView *)composeView isEditable]==NO)) {
519 NSLog(@"composeView NULL!!");
523 switch ([self messageType]) {
532 case 14:// 添付ファイルとして返信
535 NSLog(@"Unknown MessageType: %d", [self messageType]);
539 if (0 < fixLetter(self, composeView, TRUE, TRUE) || checkSubjectOnLoad(self)) {
540 if ([app operationAtOpen] == 0) {
541 NSAlert *alert = [[[NSAlert alloc] init] autorelease];
542 [alert addButtonWithTitle:@"変換"];
543 NSButton *button = [alert addButtonWithTitle:@"変換しない"];
544 button.keyEquivalent = @"\x1b";
545 [alert setShowsSuppressionButton:TRUE];
546 [alert setMessageText:@"編集前にメッセージを変換しますか?"];
547 [alert setInformativeText:@"このメッセージには ISO 2022-JP でエンコードできない文字が含まれています。"];
548 [alert setAlertStyle:NSInformationalAlertStyle];
549 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
550 [alert beginSheetModalForWindow:[self _windowLF] completionHandler:^(NSModalResponse returnCode){
551 if (returnCode == NSAlertFirstButtonReturn) {
552 fixSubjectOnLoad(self);
553 if ([app ver] == LF_ElCapitan || [app ver] == LF_Sierra ||
554 [app ver] == LF_HighSierra|| [app ver] == LF_Mojave) {
555 fixLetter(self, [self composeWebView], FALSE, TRUE);
557 } else if (returnCode == NSAlertSecondButtonReturn) {
559 if ([[alert suppressionButton] state] == NSOnState) {
560 if (returnCode == NSAlertFirstButtonReturn) {
561 [app setOperationAtOpen:1];
562 } else if (returnCode == NSAlertSecondButtonReturn) {
563 [app setOperationAtOpen:2];
568 } else if ([app operationAtOpen] == 1) {
569 fixSubjectOnLoad(self);
570 fixLetter(self, composeView, FALSE, TRUE);
571 [[self backEnd] setHasChanges:FALSE];
575 @catch (NSException * exception) {
576 NSLog(@"LetterFix: caught %@ %@", [exception name], [exception reason]);
582 void _LF_IMP_send_(id self, SEL _cmd, id arg1)
584 if ([app isActive] == NO) {
585 [self _LF_send: arg1];
590 if ([app ver] == LF_Mavericks || [app ver] == LF_Yosemite) {
591 composeView = [self webView];
592 } else if ([app ver] == LF_ElCapitan || [app ver] == LF_Sierra ||
593 [app ver] == LF_HighSierra|| [app ver] == LF_Mojave) {
594 composeView = [self composeWebView];
596 [self _LF_send: arg1];
600 backendSetPreferredEncoding([self backEnd], LF_Encoding_ISO2022JP);
601 if (0 < fixLetter(self, composeView, TRUE, FALSE)) {
602 NSAlert *alert = [[[NSAlert alloc] init] autorelease];
603 [alert addButtonWithTitle:@"変換して送信"];
604 NSButton *button = [alert addButtonWithTitle:@"キャンセル"];
605 button.keyEquivalent = @"\x1b";
606 [alert addButtonWithTitle:@"変換せずに送信"];
607 [alert addButtonWithTitle:@"変換のみ"];
608 [alert setMessageText:@"メッセージを変換して送信しますか?"];
609 [alert setInformativeText:@"送信しようとしているメッセージには ISO 2022-JP でエンコードできない文字が含まれています。"];
610 [alert setAlertStyle:NSInformationalAlertStyle];
611 [alert beginSheetModalForWindow:[self _windowLF] completionHandler:^(NSModalResponse returnCode) {
612 if (returnCode == NSAlertFirstButtonReturn) {
613 if ([app ver] == LF_Mavericks || [app ver] == LF_Yosemite) {
614 fixLetter(self, [self webView], FALSE, FALSE);
615 } else if ([app ver] == LF_ElCapitan || [app ver] == LF_Sierra ||
616 [app ver] == LF_HighSierra|| [app ver] == LF_Mojave) {
617 fixLetter(self, [self composeWebView], FALSE, FALSE);
619 if (backendGetPreferredEncoding([self backEnd]) != LF_Encoding_ISO2022JP) backendSetPreferredEncoding([self backEnd], LF_Encoding_ISO2022JP);
620 [[alert window] orderOut:arg1];
621 if (([app isCheckSubject] != NO) && checkSubject(self)) _LF_alertSubject(self, _cmd, arg1);
622 else [self _LF_send: arg1];
623 } else if (returnCode == NSAlertSecondButtonReturn) {
625 } else if (returnCode == NSAlertThirdButtonReturn) { // 変換せずに送信
626 if (backendGetPreferredEncoding([self backEnd]) == LF_Encoding_ISO2022JP) {
627 backendSetPreferredEncoding([self backEnd], LF_Encoding_Auto); // ISO2022JPのままだとISO2022JP-2とかで送ってしまう
629 [[alert window] orderOut:arg1];
630 [self _LF_send: arg1];
631 } else if (returnCode == (NSAlertThirdButtonReturn + 1)) { // 変換のみ
632 if ([app ver] == LF_Mavericks || [app ver] == LF_Yosemite) {
633 fixLetter(self, [self webView], FALSE, FALSE);
634 } else if ([app ver] == LF_ElCapitan || [app ver] == LF_Sierra ||
635 [app ver] == LF_HighSierra|| [app ver] == LF_Mojave) {
636 fixLetter(self, [self composeWebView], FALSE, FALSE);
638 if (backendGetPreferredEncoding([self backEnd]) != LF_Encoding_ISO2022JP) backendSetPreferredEncoding([self backEnd], LF_Encoding_ISO2022JP);
641 } else if (([app isCheckSubject] != NO) && checkSubject(self)) {
642 _LF_alertSubject(self, _cmd, arg1);
644 [self _LF_send: arg1];
648 void _LF_alertSubject(id self, SEL _cmd, id arg1)
650 NSAlert *alert = [[[NSAlert alloc] init] autorelease];
651 [alert addButtonWithTitle:@"変換して送信"];
652 NSButton *button = [alert addButtonWithTitle:@"キャンセル"];
653 button.keyEquivalent = @"\x1b";
654 [alert addButtonWithTitle:@"変換せずに送信"];
655 [alert addButtonWithTitle:@"変換のみ"];
656 [alert setMessageText:@"件名を変換して送信しますか?"];
657 [alert setInformativeText:@"送信するメッセージの件名には ISO 2022-JP でエンコードできない文字が含まれています。"];
658 [alert setAlertStyle:NSInformationalAlertStyle];
659 [alert beginSheetModalForWindow:[self _windowLF] completionHandler:^(NSModalResponse returnCode) {
660 if (returnCode == NSAlertFirstButtonReturn) {
662 [[alert window] orderOut:arg1];
663 [self _LF_send: arg1];
664 } else if (returnCode == NSAlertSecondButtonReturn) {
666 } else if (returnCode == NSAlertThirdButtonReturn) {
667 [[alert window] orderOut:arg1];
668 [self _LF_send: arg1];
669 } else if (returnCode == (NSAlertThirdButtonReturn + 1)) {
675 void _LF_IMP_saveDocument_(id self, SEL _cmd, id arg1)
678 if ([app willCheckOnSave] && ([app ver] == LF_Mavericks || [app ver] == LF_Yosemite)) {
679 composeView = [self webView];
680 } else if ([app willCheckOnSave] &&
681 ([app ver] == LF_ElCapitan || [app ver] == LF_Sierra ||
682 [app ver] == LF_HighSierra|| [app ver] == LF_Mojave)) {
683 composeView = [self composeWebView];
685 [self _LF_saveDocument: arg1];
689 if (([app isActive] != NO) && ([check_at_save containsObject:self]==NO) &&(0 < fixLetter(self, composeView, TRUE, FALSE))) {
690 NSAlert *alert = [[[NSAlert alloc] init] autorelease];
691 [alert addButtonWithTitle:@"変換"];
692 NSButton *button = [alert addButtonWithTitle:@"変換しない"];
693 button.keyEquivalent = @"\x1b";
694 [alert setMessageText:@"保存前にメッセージを変換しますか?"];
695 [alert setInformativeText:@"このメッセージには ISO 2022-JP でエンコードできない文字が含まれています。\n"
696 @"変換しないを選択した場合、メールの送信またはウインドウを開き直すまでエンコーディングの確認を行いません。"];
697 [alert setAlertStyle:NSWarningAlertStyle];
698 [alert beginSheetModalForWindow:[self _windowLF] completionHandler:^(NSModalResponse returnCode) {
699 if (returnCode == NSAlertFirstButtonReturn) {
700 if ([app ver] == LF_Mavericks || [app ver] == LF_Yosemite) {
701 fixLetter(self, [self webView], FALSE, FALSE);
702 } else if ([app ver] == LF_ElCapitan || [app ver] == LF_Sierra ||
703 [app ver] == LF_HighSierra|| [app ver] == LF_Mojave) {
704 fixLetter(self, [self composeWebView], FALSE, FALSE);
706 } else if (returnCode == NSAlertSecondButtonReturn) {
707 [check_at_save addObject:self];
709 [[alert window] orderOut:arg1];
710 [self _LF_saveDocument: (id)arg1];
713 [self _LF_saveDocument: arg1];
717 void _LF_IMP_animationCompleted(id self, SEL _cmd)
719 [self performSelector:@selector(isLoaded) withObject:nil afterDelay:0.5];
720 [self _LF_animationCompleted];
723 NSWindow *_LF_IMP_window(id self, SEL _cmd)
725 if ([app ver] == LF_Mavericks || [app ver] == LF_Yosemite || [app ver] == LF_ElCapitan ) {
726 return [self window];
727 } else if ([app ver] == LF_Sierra || [app ver] == LF_HighSierra||
728 [app ver] == LF_Mojave) {
729 return [[self view] window];
734 #define MVMailBundle (NSClassFromString(@"MVMailBundle"))
736 @implementation LetterFix
739 class_setSuperclass([self class], MVMailBundle); // depricated function 10.5対応のためこのワーニングだけは消せません
741 [self registerBundle];
743 khash = [[NSMutableArray alloc] initWithCapacity:1];
744 check_at_save = [[NSMutableArray alloc] initWithCapacity:1];
746 app = [[LFApp alloc] init];
748 Class editorClass = nil;
749 if ([app ver] == LF_Mavericks || [app ver] == LF_Yosemite) {
750 editorClass = NSClassFromString(@"DocumentEditor");
751 } else if ([app ver] == LF_ElCapitan || [app ver] == LF_Sierra ||
752 [app ver] == LF_HighSierra|| [app ver] == LF_Mojave) {
753 editorClass = NSClassFromString(@"ComposeViewController");
757 class_addMethod(editorClass, @selector(_windowLF), (IMP)_LF_IMP_window, "@@:");
762 if ([app ver] == LF_Mavericks || [app ver] == LF_Yosemite) {
763 swizzlingMethod(editorClass, @selector(isLoaded), @selector(_LF_isLoaded), (IMP)_LF_IMP_isLoaded);
764 swizzlingMethod(editorClass, @selector(_animationCompleted), @selector(_LF_animationCompleted), (IMP)_LF_IMP_animationCompleted);
765 } else if ([app ver] == LF_ElCapitan) {
766 swizzlingMethod(editorClass, @selector(finishLoadingEditor), @selector(_LF_finishLoadingEditor), (IMP)_LF_IMP_finishLoadingEditor);
767 } else if ([app ver] == LF_Sierra || [app ver] == LF_HighSierra || [app ver] == LF_Mojave) {
768 swizzlingMethod(editorClass, @selector(_finishLoadingEditor), @selector(_LF_finishLoadingEditor), (IMP)_LF_IMP_finishLoadingEditor);
770 swizzlingMethod(editorClass, @selector(saveDocument:), @selector(_LF_saveDocument:), (IMP)_LF_IMP_saveDocument_);
771 swizzlingMethod(editorClass, @selector(send:), @selector(_LF_send:), (IMP)_LF_IMP_send_);
773 // end of swizzling method
776 NSLog(@"LetterFix Plugin (version %s/%ld) is registered.", LETTERFIX_VERSION, (unsigned long int)[app verm]);