sources/PGPUAMclientLoginDialog.c

/*
    File:           PGPUAMclientLoginDialog.c
 
    Description:    Handles the PGPlogin Username Dialog
 
    Written by: Vinnie Moscaritolo
 
    Copyright:  © 1998 by Apple Computer, Inc., all rights reserved.
 
    Change History (most recent first):
 
    You may incorporate this sample code into your applications without
    restriction, though the sample code has been provided "AS IS" and the
    responsibility for its operation is 100% yours.  However, what you are
    not permitted to do is to redistribute the source as "DSC Sample Code"
    after having made changes. If you're going to re-distribute the source,
    we require that you make it clear in the source that the code was
    descended from Apple Sample Code, but that you've made changes.
*/
 
//------------------------------------------------------------------------------------
#pragma mark Includes
//------------------------------------------------------------------------------------
 
#include <stdio.h>
#include <string.h>
 
#include <Appearance.h>
#include <Dialogs.h>
#include <Controls.h>
#include <DateTimeUtils.h>
#include <PLStringFuncs.h>
 
 
#include "PGPUAMclient.h"
#include "PGPUAMclientLoginDialog.h"
 
#include "LaunchApplication.h"
 
#include "TMacException.h"
#include "TASIPPGPkey.h"
#include "TASIPKeyPane.h"
#include "TAboutBoxPane.h"
#include "TSetupPane.h"
#include "TPGPUAMPrefs.h"
#include "PassphraseCache.h"
 
 
//------------------------------------------------------------------------------------
#pragma mark Local Defines
//------------------------------------------------------------------------------------
 
const OSType kPGPkeysCreator    = 'pgpK';
 
#define kLoginDialogID 130
    
 static enum {
    kConnectID  = 1,
    kCancelID ,         // 2  
    kChangeKeyID,       // 37
    kUserNameID,        // 3  
    STXT4_Name,         // 4
    kInfoID,            // 5
    kIcon,              // 6
    kDisclosureTri,     // 7
    kHelpItem,          // 9
    kLaunchPGPKeysButton,// 35
    kKeyIcon,           // 10
    kProgressArrowsID,  // 12
    kDisclosureText,    // 13
    kTabsID,            // 14
    kSeperatorLine,     // 15
    KLastLoginDialogItem
    } ;
 
#define kDialogStringsID 128 
 
static enum {
    kNoDetailsStrID     =1,
    kShowDetailsStrID,
    kHideDetailsStrID,
    kServerKeyNotFound,
    kServerKeyNotFoundErrorMsg1,
    kServerKeyNotFoundErrorMsg2
};
 
    
#define kKeyStringsID 129 
static enum {
    kKeyNameStrID   =1,
    kKeyIDStrID ,
    kKeyTypeStrID,
    kKeySizeStrID,
    kKeyCreatedStrID,
    kKeyExpiresStrID,
    kKeyExpiredStrID,
    kKeyRevokedStrID,
    kKeyInvalidStrID,
    kKeyValidStrID,
    kKeyTrustedStrID,
    kKeyUnTrustedStrID,
    kKeyServerKeyIsEnabled,
    kKeyServerKeyIsDisabled,
    kKeyServerKeyIsRevoked,
    kKeyServerKeyIsExpired
    };
 
 
static enum {
    kHelpIconID         = 2200,
    kHelpIconDisabledID = 2201
};
 
static enum{
    kServerAuthPaneID = 1,
    kSetupPaneID,
    kAboutBoxPaneID
 
};
 
// ---------------------------------------------------------------------------
#pragma mark Local Globals?
// ---------------------------------------------------------------------------
 
static  TASIPPGPkey     gServerKey;
 
static  DialogPtr       gDialog = nil;
static  TPane*          gPane   = nil;
static  TPGPUAMPrefs*   gPrefs  = nil;
 
static  EventCallbackPtr gEventCallbackUPP = nil;
 
static  Boolean         gDialogForeground   = true;
static  Boolean         appleGuideAvailable = false;
 
// ---------------------------------------------------------------------------
#pragma mark Local Prototypes
// ---------------------------------------------------------------------------
static        short           GetDlgItemTop(DialogPtr dlog, int item);
static        short           GetDlgItemBottom(DialogPtr dlog, int item);
static pascal void            KeyIconDrawProc    (ControlHandle theControl, SInt16 thePart);
static pascal ControlPartCode KeyIconHitTestProc (ControlHandle theControl, Point where);
static pascal Boolean         LoginDialogFilterProc (DialogRef dialog, EventRecord *event, short *itemHit);
static        DialogPtr       NewLoginDialog(StringPtr userName, StringPtr serverName, TPGPUAMPrefs* userPrefs);
static        void            SetDialogDisclosureState (DialogPtr theDialog, Boolean expanded);
static        void            LoginDialogIdle();
static        void            UpdateLoginDialog(DialogPtr theDialog);
 
#pragma mark -
 
  
// ---------------------------------------------------------------------------
OSErr DoLoginDialog( StringPtr userName,
                     StringPtr serverName, 
                     short     *sessionRefNum,
                     TPGPUAMPrefs*  userPrefs,
                     LoginStartConnectionProcPtr startProc, 
                     CancelConnectionProcPtr    cancelProc,
                     UniversalProcPtr           eventProcUPP,
                     void *context ) 
// ---------------------------------------------------------------------------
    {
    ModalFilterUPP              loginDialogFilterProcUPP = NewModalFilterProc (LoginDialogFilterProc);
 
    ControlHandle   theControl; 
    short           itemNo;
    Size            theSize;
    long            response = 0;
    GrafPtr         savePort;
    OSErr           ErrNo       = noErr;
    Boolean         busy;
 
    if(startProc == nil) return paramErr;
    GetPort(&savePort);
    
    gEventCallbackUPP = eventProcUPP;
    gPrefs = userPrefs;
    
    try
        {
    // setup prefs timelimit
        EnablePassphraseCaching( userPrefs->GetCachePassPhrase() );
        if( userPrefs->GetCachePassPhrase() )
            SetPassphraseCacheTimeLimit( userPrefs->GetCachePassPhraseTimeLimit() );
 
     // Is apple Guide available ?
        ErrNo = Gestalt(gestaltHelpMgrAttr, &response);
        appleGuideAvailable =  (ErrNo == noErr && (response & (1 << gestaltAppleGuidePresent)));
 
    // update Key info
        gServerKey.Initialize(gAFPSrvrSig);
 
    // create Login Dialog
        ThrowIfNil( gDialog = NewLoginDialog(userName, serverName, userPrefs)); 
 
    // setup panel
        gPane = new TASIPKeyPane(gDialog, CountDITL(gDialog),  &gServerKey);
        gPane->Refresh();
        
        SetDialogDisclosureState(gDialog, userPrefs->GetDisclosureState()  );
 
    // Showtime!        
        ShowWindow(gDialog);
 
        busy = true;
        while(busy)
        {
            ModalDialog(loginDialogFilterProcUPP, &itemNo);
                
            switch(itemNo){
            
            case kCancelID:
                    if( cancelProc) cancelProc(context);    
                    busy = false;
                    ErrNo = userCanceledErr;
                    break;
                    
            case  kConnectID:
                    GetDialogItemAsControl( gDialog, kConnectID, &theControl );
                    DeactivateControl(theControl);
    // force this to no longer be the default item
    // else Appearance will re-activate it on process switch in.?
                    SetDialogDefaultItem(gDialog,0);
 
                    GetDialogItemAsControl( gDialog, kProgressArrowsID, &theControl );
                    ShowControl(theControl);
                    GetDialogItemAsControl( gDialog, kUserNameID, &theControl );
                    DeactivateControl(theControl);
                    GetControlData( theControl, 0, kControlEditTextTextTag, (Size) 63, (Ptr)&userName[1], &theSize );
                    userName[0] = (theSize &0xFF);
                    ErrNo = (startProc)( userName,serverName,sessionRefNum,userPrefs, &gServerKey, LoginDialogIdle, context );
                    busy = false;
                    break;
                    
    // toggle disclosure triangle
            case kKeyIcon:
                        GetDialogItemAsControl( gDialog, kDisclosureTri, &theControl );
                        SetControlValue(theControl,  0x1 ^ GetControlValue(theControl));
        
    // user toggled it
            case kDisclosureTri:
                        GetDialogItemAsControl( gDialog, kKeyIcon, &theControl );
                        InvalRect(&(**theControl).contrlRect);
 
                        GetDialogItemAsControl( gDialog, kDisclosureTri, &theControl );
                        SizeWindow(gDialog, 
                                        (GetDialogWindow(gDialog)->portRect.right - 
                                         GetDialogWindow(gDialog)->portRect.left),
                                    ((GetControlValue(theControl) == 0)
                                        ?GetDlgItemTop(gDialog, kSeperatorLine ) - 2 
                                        :GetDlgItemBottom(gDialog, kTabsID)) - 4,true);
                                        
                        userPrefs->SetDisclosureState ( (GetControlValue(theControl) == 1 ));
                        break;  
                        
            case kHelpItem:
                        break;
                                
            case kChangeKeyID:
                        break;
                            
            case kIcon:
                        break;
                        
            case kLaunchPGPKeysButton:
                        LaunchApplication(kPGPkeysCreator);
                        break;
                        
            case kTabsID:
                        GetDialogItemAsControl( gDialog, kTabsID, &theControl );
                        if(gPane) delete gPane; gPane = nil;
                        switch (GetControlValue( theControl ) )
                        {
                            case kServerAuthPaneID:
                                gPane = new TASIPKeyPane(gDialog, CountDITL(gDialog), &gServerKey);
                                break;
                                
                            case kSetupPaneID:
                                gPane = new TSetupPane(gDialog, CountDITL(gDialog),userPrefs );
                                break;
                            
                            case kAboutBoxPaneID:
                                gPane = new TAboutBoxPane(gDialog, CountDITL(gDialog) );
                                break;
                        }
                        if(gPane) gPane->Refresh();
                        break;
                                            
            default:
                    if((itemNo >= KLastLoginDialogItem) && gPane != nil)
                    {
                        gPane->ItemHit(itemNo);
                        UpdateLoginDialog(gDialog);
                    };
                    
                    break;
            };
        }
    
 
    }
 
// Error Reporting
    catch (...)
    {
        if(gDialog)
        {
            ClearKeyboardFocus(gDialog);
            if(gPane) delete gPane;
            DisposeDialog(gDialog);
        }
        SetPort(savePort);
        throw;
    }
 
    
    ClearKeyboardFocus(gDialog);
    if(gPane)  delete gPane;
 
    DisposeDialog(gDialog);
    gDialog = nil;
 
    SetPort(savePort);  
    
    return ErrNo;
}
 
// ---------------------------------------------------------------------------
static DialogPtr NewLoginDialog(StringPtr userName, StringPtr serverName, TPGPUAMPrefs* userPrefs )
// ---------------------------------------------------------------------------
{
    ControlUserPaneDrawUPP      keyIconDrawProcUPP       = NewControlUserPaneDrawProc(KeyIconDrawProc);
    ControlUserPaneHitTestUPP   keyIconHitTestProcUPP    = NewControlUserPaneHitTestProc(KeyIconHitTestProc);
    
    Handle              uamName;
    DialogPtr           theDialog = nil;
    ControlHandle       theControl; 
    ControlFontStyleRec fontInfo;
    Str255              text;
    
    // get Dialog Title
    uamName = Get1Resource(kUAMStr,kUAMName);
    if(!uamName) return nil;
    
    // Get the Dialog
    theDialog = GetNewDialog(kLoginDialogID, nil, (WindowPtr)-1);
    SetPort((GrafPtr) theDialog);
  
    // set dialog title
    HLock(uamName);
    SetWTitle(theDialog, (StringPtr) *uamName);
    HUnlock(uamName);
 
    // setup Dialog Items
    SetDialogCancelItem (theDialog,kCancelID);  
    SetDialogTracksCursor(theDialog,true);  
    UpdateLoginDialog(theDialog);
    
    // setup key Icon & triangle text draw routine
    GetDialogItemAsControl( theDialog, kKeyIcon, &theControl );
    SetControlData(theControl, 0, kControlUserPaneDrawProcTag, sizeof(ControlUserPaneDrawUPP), (Ptr) &keyIconDrawProcUPP);
    SetControlData(theControl, 0, kControlUserPaneHitTestProcTag, sizeof(ControlUserPaneHitTestUPP), (Ptr) &keyIconHitTestProcUPP);
 
    // load serverName info
    ParamText( serverName, "\p","\p","\p");
 
    // Preload and setup User name field
    GetDialogItemAsControl( theDialog, kUserNameID, &theControl );
    SetControlData( theControl, 0, kControlEditTextTextTag, userName[0], (Ptr)(userName+1) );
    SetKeyboardFocus(theDialog,theControl, kControlFocusNextPart);
 
    // Change key is not yet supported
    GetDialogItemAsControl( theDialog, kChangeKeyID, &theControl );
    DeactivateControl(theControl);
 
    // is appleguide around?
    GetDialogItemAsControl( theDialog, kHelpItem, &theControl );
    SetControlVisibility(theControl, appleGuideAvailable, true);
 
    fontInfo.font = kControlFontBigSystemFont;
    fontInfo.just = teJustRight;
    fontInfo.flags = kControlUseFontMask | kControlUseJustMask;
 
    // Name
    GetDialogItemAsControl( theDialog, STXT4_Name, &theControl );
    SetControlData( theControl, 0, kControlStaticTextStyleTag, sizeof fontInfo, (Ptr)&fontInfo);
 
// select proper font for disclosure text
    fontInfo.just = teJustLeft;
    fontInfo.font = kControlFontSmallSystemFont;
 
    GetDialogItemAsControl( theDialog, kDisclosureText, &theControl );
    SetControlData( theControl, 0, kControlStaticTextStyleTag, sizeof fontInfo, (Ptr)&fontInfo);
 
    return theDialog;
}
 
 
// ---------------------------------------------------------------------------
static pascal Boolean LoginDialogFilterProc
    (DialogRef dialog, EventRecord *event, short *itemHit)
// ---------------------------------------------------------------------------
{
    ModalFilterUPP  upp;
    ControlHandle   theControl; 
    Boolean handled;
    
// pre filtering
    switch(event->what)
        {
        case nullEvent:
            IdleControls(dialog);
            if(gPane) gPane->Idle();
            break;
        
        case mouseDown:
            if(( dialog == gDialog) && (gPane != nil))
                if( gPane->HandleMouseDown(event)) return true;
            break;
            
// handle switch into background?
        case osEvt:
                if ((event->message >> 24) & suspendResumeMessage )  
                {   if( gDialogForeground = (event->message  & resumeFlag))
                    {    
                        // finder resume event
                        // re-open PGP key database
                        TPGPkey::OpenKeyDefaultRing();
                        gServerKey.Initialize(gAFPSrvrSig);
                        
                        UpdateLoginDialog(gDialog);
                        
                        // update aprop panes   
                        if(gPane) gPane->Refresh();
                    } 
                    else
                    {
                        // finder suspend event
                        // close PGP key Database
                        TPGPkey::CloseKeyRing();
                    }   
                }
            break;
        }
  
  
 
    if (!GetStdFilterProc (&upp))
        handled =  CallModalFilterProc (upp,dialog,event,itemHit);
 
    if(!handled)
        CallUniversalProc( gEventCallbackUPP, kEventCallbackProcInfo, event);
 
    return handled;
}
 
// ---------------------------------------------------------------------------
static void LoginDialogIdle()
// ---------------------------------------------------------------------------
{
    EventRecord event;
    
    event.what = nullEvent;
    
    LoginDialogFilterProc (gDialog, &event, 0);
}
 
 
// ---------------------------------------------------------------------------
static void UpdateLoginDialog(DialogPtr dialog)
// ---------------------------------------------------------------------------
{
    ControlHandle       theControl; 
 
    // can we connect with this key?
    GetDialogItemAsControl( dialog, kConnectID, &theControl );
 
    if( gPrefs->GetAuthenticateServer() 
        && (!gServerKey.CanVerify() || gServerKey.IsExpired() || gServerKey.IsRevoked() || gServerKey.IsDisabled())  )
    {
        SetDialogDefaultItem(dialog, 0);            
        DeactivateControl(theControl);
    }
    else
    {
        ActivateControl(theControl);
        SetDialogDefaultItem(dialog,kConnectID);            
    }
 
}
 
 
#pragma mark -
 
// ---------------------------------------------------------------------------
static void SetDialogDisclosureState(DialogPtr theDialog, Boolean expanded)
// ---------------------------------------------------------------------------
 // activate the disclosure triangle with the proper  window default state
{
    ControlHandle       theControl; 
 
    GetDialogItemAsControl( theDialog, kDisclosureTri, &theControl );
    SetControlValue(theControl, expanded?1:0);
    SizeWindow(theDialog, 
                    (GetDialogWindow(theDialog)->portRect.right - 
                     GetDialogWindow(theDialog)->portRect.left),
                ((GetControlValue(theControl) == 0)
                    ?GetDlgItemTop(theDialog, kSeperatorLine ) - 2 
                    :GetDlgItemBottom(theDialog, kTabsID)) - 4,true);
 
}
 
 
// ---------------------------------------------------------------------------
static pascal void  KeyIconDrawProc(ControlHandle theControl, SInt16 thePart)
// ---------------------------------------------------------------------------
{
    #pragma unused( thePart )
    Rect            bounds;
    Str255          text;
    GrafPtr         savePort;
 
    GetPort(&savePort);
    SetPort((GrafPtr) gDialog);
 
    bounds = (**theControl).contrlRect;
 
    
// paint the proper Icon
    bounds.right = bounds.left+16;
    EraseRect(&bounds); 
    PlotIconID(&bounds, atNone, gDialogForeground? ttNone: ttSelectedDisabled ,  gServerKey.GetIconID());
    
// get the right text string to display for the disclosure text
    GetDialogItemAsControl( gDialog, kDisclosureTri, &theControl );
    if( gServerKey.IsInitialized() )
        GetIndString(text, kDialogStringsID,
             ( GetControlValue(theControl) == 0) ?kShowDetailsStrID:kHideDetailsStrID);
     else
        GetIndString(text, kDialogStringsID,kServerKeyNotFound);
 
 
// update the text line using an imbebded text item
    GetDialogItemAsControl( gDialog, kDisclosureText, &theControl );
    SetControlData( theControl, 0, kControlStaticTextTextTag, text[0], (Ptr)(text+1) );
  
  SetPort(savePort);
 }
 
 
// ---------------------------------------------------------------------------
 static pascal ControlPartCode KeyIconHitTestProc(ControlHandle theControl, Point where)
// ---------------------------------------------------------------------------
{
    #pragma unused( where )
 
    return kControlButtonPart;
}
 
 
#pragma mark -
 
    
 // ---------------------------------------------------------------------------
static short GetDlgItemTop(DialogPtr dlog, int item)
// ---------------------------------------------------------------------------
    {
        short type; Handle hndl; Rect box;
 
        GetDialogItem(dlog,item,&type,&hndl,&box);
        return (box.top);
    }
 
 
 // ---------------------------------------------------------------------------
static short GetDlgItemBottom(DialogPtr dlog, int item)
// ---------------------------------------------------------------------------
    {
        short type; Handle hndl; Rect box;
 
        GetDialogItem(dlog,item,&type,&hndl,&box);
        return (box.bottom);
    }