单军华
2018-07-31 21d3023a9b7b6aff68c1170e345951396b1c6cfd
screendisplay/Pods/ASIHTTPRequest/Classes/ASIAuthenticationDialog.m
New file
@@ -0,0 +1,520 @@
//
//  ASIAuthenticationDialog.m
//  Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
//
//  Created by Ben Copsey on 21/08/2009.
//  Copyright 2009 All-Seeing Interactive. All rights reserved.
//
#import "ASIAuthenticationDialog.h"
#import "ASIHTTPRequest.h"
#import <QuartzCore/QuartzCore.h>
static ASIAuthenticationDialog *sharedDialog = nil;
BOOL isDismissing = NO;
static NSMutableArray *requestsNeedingAuthentication = nil;
static const NSUInteger kUsernameRow = 0;
static const NSUInteger kUsernameSection = 0;
static const NSUInteger kPasswordRow = 1;
static const NSUInteger kPasswordSection = 0;
static const NSUInteger kDomainRow = 0;
static const NSUInteger kDomainSection = 1;
@implementation ASIAutorotatingViewController
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
   return YES;
}
@end
@interface ASIAuthenticationDialog ()
- (void)showTitle;
- (void)show;
- (NSArray *)requestsRequiringTheseCredentials;
- (void)presentNextDialog;
- (void)keyboardWillShow:(NSNotification *)notification;
- (void)orientationChanged:(NSNotification *)notification;
- (void)cancelAuthenticationFromDialog:(id)sender;
- (void)loginWithCredentialsFromDialog:(id)sender;
@property (retain) UITableView *tableView;
@end
@implementation ASIAuthenticationDialog
#pragma mark init / dealloc
+ (void)initialize
{
   if (self == [ASIAuthenticationDialog class]) {
      requestsNeedingAuthentication = [[NSMutableArray array] retain];
   }
}
+ (void)presentAuthenticationDialogForRequest:(ASIHTTPRequest *)theRequest
{
   // No need for a lock here, this will always be called on the main thread
   if (!sharedDialog) {
      sharedDialog = [[self alloc] init];
      [sharedDialog setRequest:theRequest];
      if ([theRequest authenticationNeeded] == ASIProxyAuthenticationNeeded) {
         [sharedDialog setType:ASIProxyAuthenticationType];
      } else {
         [sharedDialog setType:ASIStandardAuthenticationType];
      }
      [sharedDialog show];
   } else {
      [requestsNeedingAuthentication addObject:theRequest];
   }
}
- (id)init
{
   if ((self = [self initWithNibName:nil bundle:nil])) {
      [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
      if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
#endif
         if (![UIDevice currentDevice].generatesDeviceOrientationNotifications) {
            [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
            [self setDidEnableRotationNotifications:YES];
         }
         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
      }
#endif
   }
   return self;
}
- (void)dealloc
{
   if ([self didEnableRotationNotifications]) {
      [[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
   }
   [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
   [request release];
   [tableView release];
   [presentingController.view removeFromSuperview];
   [presentingController release];
   [super dealloc];
}
#pragma mark keyboard notifications
- (void)keyboardWillShow:(NSNotification *)notification
{
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
   if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
#endif
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_3_2
      NSValue *keyboardBoundsValue = [[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey];
#else
      NSValue *keyboardBoundsValue = [[notification userInfo] objectForKey:UIKeyboardBoundsUserInfoKey];
#endif
      CGRect keyboardBounds;
      [keyboardBoundsValue getValue:&keyboardBounds];
      UIEdgeInsets e = UIEdgeInsetsMake(0, 0, keyboardBounds.size.height, 0);
      [[self tableView] setScrollIndicatorInsets:e];
      [[self tableView] setContentInset:e];
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
   }
#endif
}
// Manually handles orientation changes on iPhone
- (void)orientationChanged:(NSNotification *)notification
{
   [self showTitle];
   UIInterfaceOrientation o = (UIInterfaceOrientation)[[UIApplication sharedApplication] statusBarOrientation];
   CGFloat angle = 0;
   switch (o) {
      case UIDeviceOrientationLandscapeLeft: angle = 90; break;
      case UIDeviceOrientationLandscapeRight: angle = -90; break;
      case UIDeviceOrientationPortraitUpsideDown: angle = 180; break;
      default: break;
   }
   CGRect f = [[UIScreen mainScreen] applicationFrame];
   // Swap the frame height and width if necessary
    if (UIDeviceOrientationIsLandscape(o)) {
      CGFloat t;
      t = f.size.width;
      f.size.width = f.size.height;
      f.size.height = t;
   }
   CGAffineTransform previousTransform = self.view.layer.affineTransform;
   CGAffineTransform newTransform = CGAffineTransformMakeRotation((CGFloat)(angle * M_PI / 180.0));
   // Reset the transform so we can set the size
   self.view.layer.affineTransform = CGAffineTransformIdentity;
   self.view.frame = (CGRect){ { 0, 0 }, f.size};
   // Revert to the previous transform for correct animation
   self.view.layer.affineTransform = previousTransform;
   [UIView beginAnimations:nil context:NULL];
   [UIView setAnimationDuration:0.3];
   // Set the new transform
   self.view.layer.affineTransform = newTransform;
   // Fix the view origin
   self.view.frame = (CGRect){ { f.origin.x, f.origin.y },self.view.frame.size};
    [UIView commitAnimations];
}
#pragma mark utilities
- (UIViewController *)presentingController
{
   if (!presentingController) {
      presentingController = [[ASIAutorotatingViewController alloc] initWithNibName:nil bundle:nil];
      // Attach to the window, but don't interfere.
      UIWindow *window = [[[UIApplication sharedApplication] windows] objectAtIndex:0];
      [window addSubview:[presentingController view]];
      [[presentingController view] setFrame:CGRectZero];
      [[presentingController view] setUserInteractionEnabled:NO];
   }
   return presentingController;
}
- (UITextField *)textFieldInRow:(NSUInteger)row section:(NSUInteger)section
{
   return [[[[[self tableView] cellForRowAtIndexPath:
            [NSIndexPath indexPathForRow:row inSection:section]]
           contentView] subviews] objectAtIndex:0];
}
- (UITextField *)usernameField
{
   return [self textFieldInRow:kUsernameRow section:kUsernameSection];
}
- (UITextField *)passwordField
{
   return [self textFieldInRow:kPasswordRow section:kPasswordSection];
}
- (UITextField *)domainField
{
   return [self textFieldInRow:kDomainRow section:kDomainSection];
}
#pragma mark show / dismiss
+ (void)dismiss
{
    UIViewController* dismisser = nil;
    if ([sharedDialog respondsToSelector:@selector(presentingViewController)]){
        dismisser = [sharedDialog presentingViewController];
    }else{
        dismisser = [sharedDialog parentViewController];
    }
    if([dismisser respondsToSelector:@selector(dismissViewControllerAnimated:completion:)]){
        [dismisser dismissViewControllerAnimated:YES completion:nil];
    }else{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
        [dismisser dismissModalViewControllerAnimated:YES];
#pragma clang diagnostic pop
    }
}
- (void)viewDidDisappear:(BOOL)animated
{
   [self retain];
   [sharedDialog release];
   sharedDialog = nil;
   [self performSelector:@selector(presentNextDialog) withObject:nil afterDelay:0];
   [self release];
}
- (void)dismiss
{
   if (self == sharedDialog) {
      [[self class] dismiss];
   } else {
        UIViewController* dismisser = nil;
      if ([self respondsToSelector:@selector(presentingViewController)]){
            dismisser = [self presentingViewController];
        }else{
            dismisser = [self parentViewController];
        }
        if([dismisser respondsToSelector:@selector(dismissViewControllerAnimated:completion:)]){
            [dismisser dismissViewControllerAnimated:YES completion:nil];
        }else{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
            [dismisser dismissModalViewControllerAnimated:YES];
#pragma clang diagnostic pop
        }
   }
}
- (void)showTitle
{
   UINavigationBar *navigationBar = [[[self view] subviews] objectAtIndex:0];
   UINavigationItem *navItem = [[navigationBar items] objectAtIndex:0];
   if (UIInterfaceOrientationIsPortrait([[UIDevice currentDevice] orientation])) {
      // Setup the title
      if ([self type] == ASIProxyAuthenticationType) {
         [navItem setPrompt:@"Login to this secure proxy server."];
      } else {
         [navItem setPrompt:@"Login to this secure server."];
      }
   } else {
      [navItem setPrompt:nil];
   }
   [navigationBar sizeToFit];
   CGRect f = [[self view] bounds];
   f.origin.y = [navigationBar frame].size.height;
   f.size.height -= f.origin.y;
   [[self tableView] setFrame:f];
}
- (void)show
{
   // Remove all subviews
   UIView *v;
   while ((v = [[[self view] subviews] lastObject])) {
      [v removeFromSuperview];
   }
   // Setup toolbar
   UINavigationBar *bar = [[[UINavigationBar alloc] init] autorelease];
   [bar setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
   UINavigationItem *navItem = [[[UINavigationItem alloc] init] autorelease];
   bar.items = [NSArray arrayWithObject:navItem];
   [[self view] addSubview:bar];
   [self showTitle];
   // Setup toolbar buttons
   if ([self type] == ASIProxyAuthenticationType) {
      [navItem setTitle:[[self request] proxyHost]];
   } else {
      [navItem setTitle:[[[self request] url] host]];
   }
   [navItem setLeftBarButtonItem:[[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelAuthenticationFromDialog:)] autorelease]];
   [navItem setRightBarButtonItem:[[[UIBarButtonItem alloc] initWithTitle:@"Login" style:UIBarButtonItemStyleDone target:self action:@selector(loginWithCredentialsFromDialog:)] autorelease]];
   // We show the login form in a table view, similar to Safari's authentication dialog
   [bar sizeToFit];
   CGRect f = [[self view] bounds];
   f.origin.y = [bar frame].size.height;
   f.size.height -= f.origin.y;
   [self setTableView:[[[UITableView alloc] initWithFrame:f style:UITableViewStyleGrouped] autorelease]];
   [[self tableView] setDelegate:self];
   [[self tableView] setDataSource:self];
   [[self tableView] setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
   [[self view] addSubview:[self tableView]];
   // Force reload the table content, and focus the first field to show the keyboard
   [[self tableView] reloadData];
   [[[[[self tableView] cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]].contentView subviews] objectAtIndex:0] becomeFirstResponder];
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
   if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
      [self setModalPresentationStyle:UIModalPresentationFormSheet];
   }
#endif
    if([[self presentingController] respondsToSelector:@selector(presentViewController:animated:completion:)]){
        [[self presentingController] presentViewController:self animated:YES completion:nil];
    }else{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
        [[self presentingController] presentModalViewController:self animated:YES];
#pragma clang diagnostic pop
    }
}
#pragma mark button callbacks
- (void)cancelAuthenticationFromDialog:(id)sender
{
   for (ASIHTTPRequest *theRequest in [self requestsRequiringTheseCredentials]) {
      [theRequest cancelAuthentication];
      [requestsNeedingAuthentication removeObject:theRequest];
   }
   [self dismiss];
}
- (NSArray *)requestsRequiringTheseCredentials
{
   NSMutableArray *requestsRequiringTheseCredentials = [NSMutableArray array];
   NSURL *requestURL = [[self request] url];
   for (ASIHTTPRequest *otherRequest in requestsNeedingAuthentication) {
      NSURL *theURL = [otherRequest url];
      if (([otherRequest authenticationNeeded] == [[self request] authenticationNeeded]) && [[theURL host] isEqualToString:[requestURL host]] && ([theURL port] == [requestURL port] || ([requestURL port] && [[theURL port] isEqualToNumber:[requestURL port]])) && [[theURL scheme] isEqualToString:[requestURL scheme]] && ((![otherRequest authenticationRealm] && ![[self request] authenticationRealm]) || ([otherRequest authenticationRealm] && [[self request] authenticationRealm] && [[[self request] authenticationRealm] isEqualToString:[otherRequest authenticationRealm]]))) {
         [requestsRequiringTheseCredentials addObject:otherRequest];
      }
   }
   [requestsRequiringTheseCredentials addObject:[self request]];
   return requestsRequiringTheseCredentials;
}
- (void)presentNextDialog
{
   if ([requestsNeedingAuthentication count]) {
      ASIHTTPRequest *nextRequest = [requestsNeedingAuthentication objectAtIndex:0];
      [requestsNeedingAuthentication removeObjectAtIndex:0];
      [[self class] presentAuthenticationDialogForRequest:nextRequest];
   }
}
- (void)loginWithCredentialsFromDialog:(id)sender
{
   for (ASIHTTPRequest *theRequest in [self requestsRequiringTheseCredentials]) {
      NSString *username = [[self usernameField] text];
      NSString *password = [[self passwordField] text];
      if (username == nil) { username = @""; }
      if (password == nil) { password = @""; }
      if ([self type] == ASIProxyAuthenticationType) {
         [theRequest setProxyUsername:username];
         [theRequest setProxyPassword:password];
      } else {
         [theRequest setUsername:username];
         [theRequest setPassword:password];
      }
      // Handle NTLM domains
      NSString *scheme = ([self type] == ASIStandardAuthenticationType) ? [[self request] authenticationScheme] : [[self request] proxyAuthenticationScheme];
      if ([scheme isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeNTLM]) {
         NSString *domain = [[self domainField] text];
         if ([self type] == ASIProxyAuthenticationType) {
            [theRequest setProxyDomain:domain];
         } else {
            [theRequest setDomain:domain];
         }
      }
      [theRequest retryUsingSuppliedCredentials];
      [requestsNeedingAuthentication removeObject:theRequest];
   }
   [self dismiss];
}
#pragma mark table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)aTableView
{
   NSString *scheme = ([self type] == ASIStandardAuthenticationType) ? [[self request] authenticationScheme] : [[self request] proxyAuthenticationScheme];
   if ([scheme isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeNTLM]) {
      return 2;
   }
   return 1;
}
- (CGFloat)tableView:(UITableView *)aTableView heightForFooterInSection:(NSInteger)section
{
   if (section == [self numberOfSectionsInTableView:aTableView]-1) {
      return 30;
   }
   return 0;
}
- (CGFloat)tableView:(UITableView *)aTableView heightForHeaderInSection:(NSInteger)section
{
   if (section == 0) {
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
      if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
         return 54;
      }
#endif
      return 30;
   }
   return 0;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
   if (section == 0) {
      return [[self request] authenticationRealm];
   }
   return nil;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_3_0
   UITableViewCell *cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease];
#else
   UITableViewCell *cell = [[[UITableViewCell alloc] initWithFrame:CGRectMake(0,0,0,0) reuseIdentifier:nil] autorelease];
#endif
   [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
   CGRect f = CGRectInset([cell bounds], 10, 10);
   UITextField *textField = [[[UITextField alloc] initWithFrame:f] autorelease];
   [textField setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
   [textField setAutocapitalizationType:UITextAutocapitalizationTypeNone];
   [textField setAutocorrectionType:UITextAutocorrectionTypeNo];
   NSUInteger s = [indexPath section];
   NSUInteger r = [indexPath row];
   if (s == kUsernameSection && r == kUsernameRow) {
      [textField setPlaceholder:@"User"];
   } else if (s == kPasswordSection && r == kPasswordRow) {
      [textField setPlaceholder:@"Password"];
      [textField setSecureTextEntry:YES];
   } else if (s == kDomainSection && r == kDomainRow) {
      [textField setPlaceholder:@"Domain"];
   }
   [cell.contentView addSubview:textField];
   return cell;
}
- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section
{
   if (section == 0) {
      return 2;
   } else {
      return 1;
   }
}
- (NSString *)tableView:(UITableView *)aTableView titleForFooterInSection:(NSInteger)section
{
   if (section == [self numberOfSectionsInTableView:aTableView]-1) {
      // If we're using Basic authentication and the connection is not using SSL, we'll show the plain text message
      if ([[[self request] authenticationScheme] isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeBasic] && ![[[[self request] url] scheme] isEqualToString:@"https"]) {
         return @"Password will be sent in the clear.";
      // We are using Digest, NTLM, or any scheme over SSL
      } else {
         return @"Password will be sent securely.";
      }
   }
   return nil;
}
#pragma mark -
@synthesize request;
@synthesize type;
@synthesize tableView;
@synthesize didEnableRotationNotifications;
@synthesize presentingController;
@end