- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / cocoa / external_protocol_dialog.mm
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import "chrome/browser/ui/cocoa/external_protocol_dialog.h"
6
7 #include "base/message_loop/message_loop.h"
8 #include "base/metrics/histogram.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/sys_string_conversions.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "chrome/browser/external_protocol/external_protocol_handler.h"
13 #include "grit/chromium_strings.h"
14 #include "grit/generated_resources.h"
15 #include "ui/base/l10n/l10n_util_mac.h"
16 #include "ui/gfx/text_elider.h"
17
18 ///////////////////////////////////////////////////////////////////////////////
19 // ExternalProtocolHandler
20
21 // static
22 void ExternalProtocolHandler::RunExternalProtocolDialog(
23     const GURL& url, int render_process_host_id, int routing_id) {
24   [[ExternalProtocolDialogController alloc] initWithGURL:&url];
25 }
26
27 ///////////////////////////////////////////////////////////////////////////////
28 // ExternalProtocolDialogController
29
30 @interface ExternalProtocolDialogController(Private)
31 - (void)alertEnded:(NSAlert *)alert
32         returnCode:(int)returnCode
33        contextInfo:(void*)contextInfo;
34 - (string16)appNameForProtocol;
35 @end
36
37 @implementation ExternalProtocolDialogController
38 - (id)initWithGURL:(const GURL*)url {
39   DCHECK_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type());
40
41   if (!(self = [super init]))
42     return nil;
43
44   url_ = *url;
45   creation_time_ = base::Time::Now();
46
47   string16 appName = [self appNameForProtocol];
48   if (appName.length() == 0) {
49     // No registered apps for this protocol; give up and go home.
50     [self autorelease];
51     return nil;
52   }
53
54   alert_ = [[NSAlert alloc] init];
55
56   [alert_ setMessageText:
57       l10n_util::GetNSStringWithFixup(IDS_EXTERNAL_PROTOCOL_TITLE)];
58
59   NSButton* allowButton = [alert_ addButtonWithTitle:
60       l10n_util::GetNSStringWithFixup(IDS_EXTERNAL_PROTOCOL_OK_BUTTON_TEXT)];
61   [allowButton setKeyEquivalent:@""];  // disallow as default
62   [alert_ addButtonWithTitle:
63       l10n_util::GetNSStringWithFixup(
64         IDS_EXTERNAL_PROTOCOL_CANCEL_BUTTON_TEXT)];
65
66   const int kMaxUrlWithoutSchemeSize = 256;
67   string16 elided_url_without_scheme;
68   gfx::ElideString(ASCIIToUTF16(url_.possibly_invalid_spec()),
69                   kMaxUrlWithoutSchemeSize, &elided_url_without_scheme);
70
71   NSString* urlString = l10n_util::GetNSStringFWithFixup(
72       IDS_EXTERNAL_PROTOCOL_INFORMATION,
73       ASCIIToUTF16(url_.scheme() + ":"),
74       elided_url_without_scheme);
75   NSString* appString = l10n_util::GetNSStringFWithFixup(
76       IDS_EXTERNAL_PROTOCOL_APPLICATION_TO_LAUNCH,
77       appName);
78   NSString* warningString =
79       l10n_util::GetNSStringWithFixup(IDS_EXTERNAL_PROTOCOL_WARNING);
80   NSString* informativeText =
81       [NSString stringWithFormat:@"%@\n\n%@\n\n%@",
82                                  urlString,
83                                  appString,
84                                  warningString];
85
86   [alert_ setInformativeText:informativeText];
87
88   [alert_ setShowsSuppressionButton:YES];
89   [[alert_ suppressionButton] setTitle:
90       l10n_util::GetNSStringWithFixup(IDS_EXTERNAL_PROTOCOL_CHECKBOX_TEXT)];
91
92   [alert_ beginSheetModalForWindow:nil  // nil here makes it app-modal
93                      modalDelegate:self
94                     didEndSelector:@selector(alertEnded:returnCode:contextInfo:)
95                        contextInfo:nil];
96
97   return self;
98 }
99
100 - (void)dealloc {
101   [alert_ release];
102
103   [super dealloc];
104 }
105
106 - (void)alertEnded:(NSAlert *)alert
107         returnCode:(int)returnCode
108        contextInfo:(void*)contextInfo {
109   ExternalProtocolHandler::BlockState blockState =
110       ExternalProtocolHandler::UNKNOWN;
111   switch (returnCode) {
112     case NSAlertFirstButtonReturn:
113       blockState = ExternalProtocolHandler::DONT_BLOCK;
114       break;
115     case NSAlertSecondButtonReturn:
116       blockState = ExternalProtocolHandler::BLOCK;
117       break;
118     default:
119       NOTREACHED();
120   }
121
122   // Set the "don't warn me again" info.
123   if ([[alert_ suppressionButton] state] == NSOnState)
124     ExternalProtocolHandler::SetBlockState(url_.scheme(), blockState);
125
126   if (blockState == ExternalProtocolHandler::DONT_BLOCK) {
127     UMA_HISTOGRAM_LONG_TIMES("clickjacking.launch_url",
128                              base::Time::Now() - creation_time_);
129
130     ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(url_);
131   }
132
133   [self autorelease];
134 }
135
136 - (string16)appNameForProtocol {
137   NSURL* url = [NSURL URLWithString:
138       base::SysUTF8ToNSString(url_.possibly_invalid_spec())];
139   CFURLRef openingApp = NULL;
140   OSStatus status = LSGetApplicationForURL((CFURLRef)url,
141                                            kLSRolesAll,
142                                            NULL,
143                                            &openingApp);
144   if (status != noErr) {
145     // likely kLSApplicationNotFoundErr
146     return string16();
147   }
148   NSString* appPath = [(NSURL*)openingApp path];
149   CFRelease(openingApp);  // NOT A BUG; LSGetApplicationForURL retains for us
150   NSString* appDisplayName =
151       [[NSFileManager defaultManager] displayNameAtPath:appPath];
152
153   return base::SysNSStringToUTF16(appDisplayName);
154 }
155
156 @end