LayoutTests:
[WebKit-https.git] / WebKit / Panels / WebAuthenticationPanel.m
1 /*
2  * Copyright (C) 2005 Apple Computer, Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #import <WebKit/WebAuthenticationPanel.h>
30
31 #import <Foundation/NSURLAuthenticationChallenge.h>
32 #import <Foundation/NSURLProtectionSpace.h>
33 #import <Foundation/NSURLCredential.h>
34 #import <JavaScriptCore/Assertions.h>
35 #import <WebKit/WebLocalizableStrings.h>
36 #import <WebKit/WebNSURLExtras.h>
37
38 #import <WebKit/WebNSControlExtras.h>
39
40 #define WebAuthenticationPanelNibName @"WebAuthenticationPanel"
41
42 @implementation WebAuthenticationPanel
43
44 -(id)initWithCallback:(id)cb selector:(SEL)sel
45 {
46     self = [self init];
47     if (self != nil) {
48         callback = [cb retain];
49         selector = sel;
50     }
51     return self;
52 }
53
54
55 - (void)dealloc
56 {
57     [panel release];
58
59     [callback release];
60     
61     [super dealloc];
62 }
63
64 // IB actions
65
66 - (IBAction)cancel:(id)sender
67 {
68     // This is required because the body of this method is going to
69     // remove all of the panel's remaining refs, which can cause a
70     // crash later when finishing button hit tracking.  So we make
71     // sure it lives on a bit longer.
72     [[panel retain] autorelease];
73     
74     // This is required as a workaround for AppKit issue 4118422
75     [[self retain] autorelease];
76
77     [panel close];
78     if (usingSheet) {
79         [[NSApplication sharedApplication] endSheet:panel returnCode:1];
80     } else {
81         [[NSApplication sharedApplication] stopModalWithCode:1];
82     }
83 }
84
85 - (IBAction)logIn:(id)sender
86 {
87     // This is required because the body of this method is going to
88     // remove all of the panel's remaining refs, which can cause a
89     // crash later when finishing button hit tracking.  So we make
90     // sure it lives on a bit longer.
91     [[panel retain] autorelease];
92
93     [panel close];
94     if (usingSheet) {
95         [[NSApplication sharedApplication] endSheet:panel returnCode:0];
96     } else {
97         [[NSApplication sharedApplication] stopModalWithCode:0];
98     }
99 }
100
101 - (BOOL)loadNib
102 {
103     if (!nibLoaded) {
104         if ([NSBundle loadNibNamed:WebAuthenticationPanelNibName owner:self]) {
105             nibLoaded = YES;
106             [imageView setImage:[NSImage imageNamed:@"NSApplicationIcon"]];
107         } else {
108             LOG_ERROR("couldn't load nib named '%@'", WebAuthenticationPanelNibName);
109             return FALSE;
110         }
111     }
112     return TRUE;
113 }
114
115 // Methods related to displaying the panel
116
117 -(void)setUpForChallenge:(NSURLAuthenticationChallenge *)chall
118 {
119     [self loadNib];
120
121     NSURLProtectionSpace *space = [chall protectionSpace];
122
123     NSString *host;
124     if ([space port] == 0) {
125         host = [space host];
126     } else {
127         host = [NSString stringWithFormat:@"%@:%u", [space host], [space port]];
128     }
129
130     NSString *realm = [space realm];
131     NSString *message;
132
133     if ([chall previousFailureCount] == 0) {
134         if ([space isProxy]) {
135             message = [NSString stringWithFormat:UI_STRING("To view this page, you need to log in to the %@ proxy server %@.",
136                                                            "prompt string in authentication panel"),
137                 [space proxyType], host];
138         } else {
139             message = [NSString stringWithFormat:UI_STRING("To view this page, you need to log in to area “%@” on %@.",
140                                                            "prompt string in authentication panel"),
141                 realm, host];
142         }
143     } else {
144         if ([space isProxy]) {
145             message = [NSString stringWithFormat:UI_STRING("The name or password entered for the %@ proxy server %@ was incorrect. Please try again.",
146                                                            "prompt string in authentication panel"),
147                 [space proxyType], host];
148         } else {
149             message = [NSString stringWithFormat:UI_STRING("The name or password entered for area “%@” on %@ was incorrect. Please try again.",
150                                                            "prompt string in authentication panel"),
151                 realm, host];
152         }
153     }
154
155     [mainLabel setStringValue:message];
156     [mainLabel sizeToFitAndAdjustWindowHeight];
157
158     if ([space receivesCredentialSecurely]) {
159         [smallLabel setStringValue:
160             UI_STRING("Your log-in information will be sent securely.",
161                 "message in authentication panel")];
162     } else {
163         [smallLabel setStringValue:
164             UI_STRING("Your password will be sent in the clear.",
165                 "message in authentication panel")];
166     }
167
168     if ([[chall proposedCredential] user] != nil) {
169         [username setStringValue:[[chall proposedCredential] user]];
170         [panel setInitialFirstResponder:password];
171     } else {
172         [username setStringValue:@""];
173         [password setStringValue:@""];
174         [panel setInitialFirstResponder:username];
175     }
176 }
177
178 - (void)runAsModalDialogWithChallenge:(NSURLAuthenticationChallenge *)chall
179 {
180     [self setUpForChallenge:chall];
181     usingSheet = FALSE;
182     NSURLCredential *credential = nil;
183
184     if ([[NSApplication sharedApplication] runModalForWindow:panel] == 0) {
185         credential = [NSURLCredential credentialWithUser:[username stringValue] password:[password stringValue] persistence:([remember state] == NSOnState) ? NSURLCredentialPersistencePermanent : NSURLCredentialPersistenceForSession];
186     }
187
188     [callback performSelector:selector withObject:chall withObject:credential];
189 }
190
191 - (void)runAsSheetOnWindow:(NSWindow *)window withChallenge:(NSURLAuthenticationChallenge *)chall
192 {
193     ASSERT(!usingSheet);
194
195     [self setUpForChallenge:chall];
196
197     usingSheet = TRUE;
198     challenge = [chall retain];
199     
200     [[NSApplication sharedApplication] beginSheet:panel modalForWindow:window modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:NULL];
201 }
202
203 - (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void  *)contextInfo
204 {
205     NSURLCredential *credential = nil;
206     NSURLAuthenticationChallenge *chall;
207
208     ASSERT(usingSheet);
209     ASSERT(challenge != nil);
210
211     if (returnCode == 0) {
212         credential = [NSURLCredential credentialWithUser:[username stringValue] password:[password stringValue] persistence:([remember state] == NSOnState) ? NSURLCredentialPersistencePermanent : NSURLCredentialPersistenceForSession];
213     }
214
215     // We take this tricky approach to nilling out and releasing the challenge
216     // because the callback below might remove our last ref.
217     chall = challenge;
218     challenge = nil;
219     [callback performSelector:selector withObject:chall withObject:credential];
220     [chall release];
221 }
222
223 @end
224
225 @implementation NonBlockingPanel
226
227 - (BOOL)_blocksActionWhenModal:(SEL)theAction
228 {
229     // This override of a private AppKit method allows the user to quit when a login dialog
230     // is onscreen, which is nice in general but in particular prevents pathological cases
231     // like 3744583 from requiring a Force Quit.
232     //
233     // It would be nice to allow closing the individual window as well as quitting the app when
234     // a login sheet is up, but this _blocksActionWhenModal: mechanism doesn't support that.
235     // This override matches those in NSOpenPanel and NSToolbarConfigPanel.
236     if (theAction == @selector(terminate:)) {
237         return NO;
238     }
239     return YES;
240 }
241
242 @end