Upstream version 10.39.225.0
[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 "chrome/grit/chromium_strings.h"
14 #include "chrome/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                                      renderProcessHostId:render_process_host_id
26                                                routingId:routing_id];
27 }
28
29 ///////////////////////////////////////////////////////////////////////////////
30 // ExternalProtocolDialogController
31
32 @interface ExternalProtocolDialogController(Private)
33 - (void)alertEnded:(NSAlert *)alert
34         returnCode:(int)returnCode
35        contextInfo:(void*)contextInfo;
36 - (base::string16)appNameForProtocol;
37 @end
38
39 @implementation ExternalProtocolDialogController
40 - (id)initWithGURL:(const GURL*)url
41     renderProcessHostId:(int)renderProcessHostId
42     routingId:(int)routingId {
43   DCHECK(base::MessageLoopForUI::IsCurrent());
44
45   if (!(self = [super init]))
46     return nil;
47
48   url_ = *url;
49   render_process_host_id_ = renderProcessHostId;
50   routing_id_ = routingId;
51   creation_time_ = base::Time::Now();
52
53   base::string16 appName = [self appNameForProtocol];
54   if (appName.length() == 0) {
55     // No registered apps for this protocol; give up and go home.
56     [self autorelease];
57     return nil;
58   }
59
60   alert_ = [[NSAlert alloc] init];
61
62   [alert_ setMessageText:
63       l10n_util::GetNSStringWithFixup(IDS_EXTERNAL_PROTOCOL_TITLE)];
64
65   NSButton* allowButton = [alert_ addButtonWithTitle:
66       l10n_util::GetNSStringWithFixup(IDS_EXTERNAL_PROTOCOL_OK_BUTTON_TEXT)];
67   [allowButton setKeyEquivalent:@""];  // disallow as default
68   [alert_ addButtonWithTitle:
69       l10n_util::GetNSStringWithFixup(
70         IDS_EXTERNAL_PROTOCOL_CANCEL_BUTTON_TEXT)];
71
72   const int kMaxUrlWithoutSchemeSize = 256;
73   base::string16 elided_url_without_scheme;
74   gfx::ElideString(base::ASCIIToUTF16(url_.possibly_invalid_spec()),
75                   kMaxUrlWithoutSchemeSize, &elided_url_without_scheme);
76
77   NSString* urlString = l10n_util::GetNSStringFWithFixup(
78       IDS_EXTERNAL_PROTOCOL_INFORMATION,
79       base::ASCIIToUTF16(url_.scheme() + ":"),
80       elided_url_without_scheme);
81   NSString* appString = l10n_util::GetNSStringFWithFixup(
82       IDS_EXTERNAL_PROTOCOL_APPLICATION_TO_LAUNCH,
83       appName);
84   NSString* warningString =
85       l10n_util::GetNSStringWithFixup(IDS_EXTERNAL_PROTOCOL_WARNING);
86   NSString* informativeText =
87       [NSString stringWithFormat:@"%@\n\n%@\n\n%@",
88                                  urlString,
89                                  appString,
90                                  warningString];
91
92   [alert_ setInformativeText:informativeText];
93
94   [alert_ setShowsSuppressionButton:YES];
95   [[alert_ suppressionButton] setTitle:
96       l10n_util::GetNSStringWithFixup(IDS_EXTERNAL_PROTOCOL_CHECKBOX_TEXT)];
97
98   [alert_ beginSheetModalForWindow:nil  // nil here makes it app-modal
99                      modalDelegate:self
100                     didEndSelector:@selector(alertEnded:returnCode:contextInfo:)
101                        contextInfo:nil];
102
103   return self;
104 }
105
106 - (void)dealloc {
107   [alert_ release];
108
109   [super dealloc];
110 }
111
112 - (void)alertEnded:(NSAlert *)alert
113         returnCode:(int)returnCode
114        contextInfo:(void*)contextInfo {
115   ExternalProtocolHandler::BlockState blockState =
116       ExternalProtocolHandler::UNKNOWN;
117   switch (returnCode) {
118     case NSAlertFirstButtonReturn:
119       blockState = ExternalProtocolHandler::DONT_BLOCK;
120       break;
121     case NSAlertSecondButtonReturn:
122       blockState = ExternalProtocolHandler::BLOCK;
123       break;
124     default:
125       NOTREACHED();
126   }
127
128   // Set the "don't warn me again" info.
129   if ([[alert_ suppressionButton] state] == NSOnState)
130     ExternalProtocolHandler::SetBlockState(url_.scheme(), blockState);
131
132   if (blockState == ExternalProtocolHandler::DONT_BLOCK) {
133     UMA_HISTOGRAM_LONG_TIMES("clickjacking.launch_url",
134                              base::Time::Now() - creation_time_);
135
136     ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(
137         url_, render_process_host_id_, routing_id_);
138   }
139
140   [self autorelease];
141 }
142
143 - (base::string16)appNameForProtocol {
144   NSURL* url = [NSURL URLWithString:
145       base::SysUTF8ToNSString(url_.possibly_invalid_spec())];
146   CFURLRef openingApp = NULL;
147   OSStatus status = LSGetApplicationForURL((CFURLRef)url,
148                                            kLSRolesAll,
149                                            NULL,
150                                            &openingApp);
151   if (status != noErr) {
152     // likely kLSApplicationNotFoundErr
153     return base::string16();
154   }
155   NSString* appPath = [(NSURL*)openingApp path];
156   CFRelease(openingApp);  // NOT A BUG; LSGetApplicationForURL retains for us
157   NSString* appDisplayName =
158       [[NSFileManager defaultManager] displayNameAtPath:appPath];
159
160   return base::SysNSStringToUTF16(appDisplayName);
161 }
162
163 @end