X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/cc2be455e222327e259a69c019fe7a25d2e32bc8..973612f5e86c9eaabc812a47d81c5cb14f672249:/mac/mac.c diff --git a/mac/mac.c b/mac/mac.c index 5abc49a9..9e1d1f30 100644 --- a/mac/mac.c +++ b/mac/mac.c @@ -1,6 +1,6 @@ -/* $Id: mac.c,v 1.44 2003/02/04 00:33:11 ben Exp $ */ +/* $Id$ */ /* - * Copyright (c) 1999 Ben Harris + * Copyright (c) 1999, 2003 Ben Harris * All rights reserved. * * Permission is hereby granted, free of charge, to any person @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -61,17 +62,16 @@ #include "macresid.h" #include "putty.h" #include "ssh.h" +#include "terminal.h" #include "mac.h" -#if !TARGET_API_MAC_CARBON -QDGlobals qd; -#endif - Session *sesslist; static int cold = 1; static int borednow = FALSE; struct mac_gestalts mac_gestalts; +UInt32 sleeptime; +static long timing_next_time; static void mac_startup(void); static void mac_eventloop(void); @@ -80,13 +80,13 @@ static void mac_event(EventRecord *); static void mac_contentclick(WindowPtr, EventRecord *); static void mac_growwindow(WindowPtr, EventRecord *); static void mac_activatewindow(WindowPtr, EventRecord *); +static void mac_suspendresume(EventRecord *); static void mac_activateabout(WindowPtr, EventRecord *); static void mac_updatewindow(WindowPtr); static void mac_updatelicence(WindowPtr); static void mac_keypress(EventRecord *); static int mac_windowtype(WindowPtr); static void mac_menucommand(long); -static void mac_openabout(void); static void mac_openlicence(void); static void mac_adjustcursor(RgnHandle); static void mac_adjustmenus(void); @@ -161,6 +161,9 @@ static void mac_startup(void) { if (Gestalt(gestaltWindowMgrAttr, &mac_gestalts.windattr) != noErr || &SetWindowContentColor == kUnresolvedCFragSymbolAddress) mac_gestalts.windattr = 0; + /* Mac OS 8.5 Menu Manager? */ + if (Gestalt(gestaltMenuMgrAttr, &mac_gestalts.menuattr) != noErr) + mac_gestalts.menuattr = 0; #endif /* Text Encoding Conversion Manager? */ if ( @@ -193,6 +196,11 @@ static void mac_startup(void) { fatalbox("Unable to create menu bar."); SetMenuBar(menuBar); AppendResMenu(GetMenuHandle(mApple), 'DRVR'); + if (mac_gestalts.menuattr & gestaltMenuMgrAquaLayoutMask) { + DeleteMenuItem(GetMenuHandle(mFile), iQuit); + /* Also delete the separator above the Quit item. */ + DeleteMenuItem(GetMenuHandle(mFile), iQuit - 1); + } mac_adjustmenus(); DrawMenuBar(); InitCursor(); @@ -237,22 +245,48 @@ static void mac_startup(void) { NewAEEventHandlerUPP(&mac_aevt_quit), 0, FALSE); } +void timer_change_notify(long next) +{ + timing_next_time = next; +} + static void mac_eventloop(void) { Boolean gotevent; EventRecord event; RgnHandle cursrgn; + long next; + long ticksleft; cursrgn = NewRgn(); + sleeptime = 0; for (;;) { - mac_adjustcursor(cursrgn); - gotevent = WaitNextEvent(everyEvent, &event, LONG_MAX, cursrgn); + ticksleft=timing_next_time-GETTICKCOUNT(); + if (sleeptime > ticksleft && ticksleft >=0) + sleeptime=ticksleft; + gotevent = WaitNextEvent(everyEvent, &event, sleeptime, cursrgn); + if (timing_next_time <= GETTICKCOUNT()) { + if (run_timers(timing_next_time, &next)) { + timer_change_notify(next); + } + } + + /* + * XXX For now, limit sleep time to 1/10 s to work around + * wake-before-sleep race in MacTCP code. + */ + sleeptime = 6; mac_adjustcursor(cursrgn); - if (gotevent) + if (gotevent) { + /* Ensure we get a null event when the real ones run out. */ + sleeptime = 0; mac_event(&event); - if (borednow) - cleanup_exit(0); - sk_poll(); - mac_pollterm(); + if (borednow) + cleanup_exit(0); + } + if (!gotevent) + sk_poll(); + if (mac_gestalts.apprvers >= 0x100 && mac_frontwindow() != NULL) + IdleControls(mac_frontwindow()); } DisposeRgn(cursrgn); } @@ -328,152 +362,59 @@ static void mac_event(EventRecord *event) { } break; #endif + case osEvt: + switch ((event->message & osEvtMessageMask) >> 24) { + case suspendResumeMessage: + mac_suspendresume(event); + break; + } + break; case kHighLevelEvent: AEProcessAppleEvent(event); /* errors? */ break; } } -static void mac_contentclick(WindowPtr window, EventRecord *event) { - short item; - DialogRef dialog; +static void mac_contentclick(WindowPtr window, EventRecord *event) +{ - switch (mac_windowtype(window)) { - case wTerminal: - mac_clickterm(window, event); - break; - case wAbout: - dialog = GetDialogFromWindow(window); - if (DialogSelect(event, &dialog, &item)) - switch (item) { - case wiAboutLicence: - mac_openlicence(); - break; - } - break; - case wSettings: - mac_clickdlg(window, event); - break; - } + if (mac_wininfo(window)->click != NULL) + (*mac_wininfo(window)->click)(window, event); } -static void mac_growwindow(WindowPtr window, EventRecord *event) { +static void mac_growwindow(WindowPtr window, EventRecord *event) +{ - switch (mac_windowtype(window)) { - case wTerminal: - mac_growterm(window, event); - } + if (mac_wininfo(window)->grow != NULL) + (*mac_wininfo(window)->grow)(window, event); } -static void mac_activatewindow(WindowPtr window, EventRecord *event) { - int active; +static void mac_activatewindow(WindowPtr window, EventRecord *event) +{ - active = (event->modifiers & activeFlag) != 0; mac_adjustmenus(); - switch (mac_windowtype(window)) { - case wTerminal: - mac_activateterm(window, active); - break; - case wSettings: - mac_activatedlg(window, event); - break; - case wAbout: - mac_activateabout(window, event); - break; - } -} - -static void mac_activateabout(WindowPtr window, EventRecord *event) { - DialogRef dialog; - DialogItemType itemtype; - Handle itemhandle; - short item; - Rect itemrect; - int active; - - dialog = GetDialogFromWindow(window); - active = (event->modifiers & activeFlag) != 0; - GetDialogItem(dialog, wiAboutLicence, &itemtype, &itemhandle, &itemrect); - HiliteControl((ControlHandle)itemhandle, active ? 0 : 255); - DialogSelect(event, &dialog, &item); + if (mac_wininfo(window)->activate != NULL) + (*mac_wininfo(window)->activate)(window, event); } static void mac_updatewindow(WindowPtr window) { -#if TARGET_API_MAC_CARBON - RgnHandle rgn; -#endif - switch (mac_windowtype(window)) { - case wTerminal: - mac_updateterm(window); - break; - case wAbout: - case wSettings: - BeginUpdate(window); -#if TARGET_API_MAC_CARBON - rgn = NewRgn(); - GetPortVisibleRegion(GetWindowPort(window), rgn); - UpdateDialog(GetDialogFromWindow(window), rgn); - DisposeRgn(rgn); -#else - UpdateDialog(window, window->visRgn); -#endif - EndUpdate(window); - break; - case wLicence: - mac_updatelicence(window); - break; - } -} - -static void mac_updatelicence(WindowPtr window) -{ - Handle h; - int len; - long fondsize; - Rect textrect; - - SetPort((GrafPtr)GetWindowPort(window)); - BeginUpdate(window); - fondsize = GetScriptVariable(smRoman, smScriptSmallFondSize); - TextFont(HiWord(fondsize)); - TextSize(LoWord(fondsize)); - h = Get1Resource('TEXT', wLicence); - len = GetResourceSizeOnDisk(h); -#if TARGET_API_MAC_CARBON - GetPortBounds(GetWindowPort(window), &textrect); -#else - textrect = window->portRect; -#endif - if (h != NULL) { - HLock(h); - TETextBox(*h, len, &textrect, teFlushDefault); - HUnlock(h); - } - EndUpdate(window); + if (mac_wininfo(window)->update != NULL) + (*mac_wininfo(window)->update)(window); } /* * Work out what kind of window we're dealing with. - * Concept shamelessly nicked from SurfWriter. */ -static int mac_windowtype(WindowPtr window) { - int kind; - long refcon; - - if (window == NULL) - return wNone; - kind = GetWindowKind(window); - if (kind < 0) +static int mac_windowtype(WindowPtr window) +{ + +#if !TARGET_API_MAC_CARBON + if (GetWindowKind(window) < 0) return wDA; - if (GetWVariant(window) == zoomDocProc) - return wTerminal; - refcon = GetWRefCon(window); - if (refcon < 1024) - return refcon; - else - return wSettings; +#endif + return ((WinInfo *)GetWRefCon(window))->wtype; } /* @@ -482,7 +423,7 @@ static int mac_windowtype(WindowPtr window) { static void mac_keypress(EventRecord *event) { WindowPtr window; - window = FrontWindow(); + window = mac_frontwindow(); /* * Check for a command-key combination, but ignore it if it counts * as a meta-key combination and we're in a terminal window. @@ -493,11 +434,8 @@ static void mac_keypress(EventRecord *event) { mac_adjustmenus(); mac_menucommand(MenuKey(event->message & charCodeMask)); } else { - switch (mac_windowtype(window)) { - case wTerminal: - mac_keyterm(window, event); - break; - } + if (window != NULL && mac_wininfo(window)->key != NULL) + (*mac_wininfo(window)->key)(window, event); } } @@ -510,7 +448,7 @@ static void mac_menucommand(long result) { menu = HiWord(result); item = LoWord(result); - window = FrontWindow(); + window = mac_frontwindow(); /* Things which do the same whatever window we're in. */ switch (menu) { case mApple: @@ -534,6 +472,9 @@ static void mac_menucommand(long result) { case iOpen: mac_opensession(); goto done; + case iChange: + mac_reconfig(); + goto done; case iClose: mac_closewindow(window); goto done; @@ -553,71 +494,49 @@ static void mac_menucommand(long result) { break; } /* If we get here, handling is up to window-specific code. */ - switch (mac_windowtype(window)) { - case wTerminal: - mac_menuterm(window, menu, item); - break; - } + if (window != NULL && mac_wininfo(window)->menu != NULL) + (*mac_wininfo(window)->menu)(window, menu, item); + done: HiliteMenu(0); } -static void mac_openabout(void) { - DialogItemType itemtype; - Handle item; - VersRecHndl vers; - Rect box; - StringPtr longvers; - - if (windows.about) - SelectWindow(windows.about); - else { - windows.about = - GetDialogWindow(GetNewDialog(wAbout, NULL, (WindowPtr)-1)); - vers = (VersRecHndl)Get1Resource('vers', 1); - if (vers != NULL && *vers != NULL) { - longvers = (*vers)->shortVersion + (*vers)->shortVersion[0] + 1; - GetDialogItem(GetDialogFromWindow(windows.about), wiAboutVersion, - &itemtype, &item, &box); - assert(itemtype & kStaticTextDialogItem); - SetDialogItemText(item, longvers); - } - ShowWindow(windows.about); - } -} - -static void mac_openlicence(void) { - - if (windows.licence) - SelectWindow(windows.licence); - else { - windows.licence = GetNewWindow(wLicence, NULL, (WindowPtr)-1); - ShowWindow(windows.licence); - } -} - static void mac_closewindow(WindowPtr window) { switch (mac_windowtype(window)) { #if !TARGET_API_MAC_CARBON case wDA: - CloseDeskAcc(((WindowPeek)window)->windowKind); + CloseDeskAcc(GetWindowKind(window)); break; #endif - case wTerminal: - mac_closeterm(window); - break; - case wAbout: - windows.about = NULL; - DisposeDialog(GetDialogFromWindow(window)); - break; - case wLicence: - windows.licence = NULL; - DisposeWindow(window); + default: + if (mac_wininfo(window)->close != NULL) + (*mac_wininfo(window)->close)(window); break; } } +static void mac_suspendresume(EventRecord *event) +{ + WindowPtr front; + EventRecord fakeevent; + + /* + * We're called either before we're suspended or after we're + * resumed, so we're the front application at this point. + */ + front = FrontWindow(); + if (front != NULL) { + fakeevent.what = activateEvt; + fakeevent.message = (UInt32)front; + fakeevent.when = event->when; + fakeevent.where = event->where; + fakeevent.modifiers = + (event->message & resumeFlag) ? activeFlag : 0; + mac_activatewindow(front, &fakeevent); + } +} + static void mac_zoomwindow(WindowPtr window, short part) { /* FIXME: do something */ @@ -634,7 +553,7 @@ static void mac_adjustmenus(void) { WindowPtr window; MenuHandle menu; - window = FrontWindow(); + window = mac_frontwindow(); menu = GetMenuHandle(mApple); EnableItem(menu, 0); EnableItem(menu, iAbout); @@ -648,24 +567,17 @@ static void mac_adjustmenus(void) { DisableItem(menu, iClose); EnableItem(menu, iQuit); - switch (mac_windowtype(window)) { - case wSettings: - DisableItem(menu, iSave); /* XXX enable if modified */ - EnableItem(menu, iSaveAs); - EnableItem(menu, iDuplicate); - menu = GetMenuHandle(mEdit); - DisableItem(menu, 0); - break; - case wTerminal: - mac_adjusttermmenus(window); - break; - default: + if (window != NULL && mac_wininfo(window)->adjustmenus != NULL) + (*mac_wininfo(window)->adjustmenus)(window); + else { + DisableItem(menu, iChange); DisableItem(menu, iSave); DisableItem(menu, iSaveAs); DisableItem(menu, iDuplicate); menu = GetMenuHandle(mEdit); DisableItem(menu, 0); - break; + menu = GetMenuHandle(mWindow); + DisableItem(menu, 0); /* Until we get more than 1 item on it. */ } DrawMenuBar(); } @@ -706,11 +618,9 @@ static void mac_adjustcursor(RgnHandle cursrgn) { #endif } } else { - switch (mac_windowtype(window)) { - case wTerminal: - mac_adjusttermcursor(window, mouse, cursrgn); - break; - default: + if (mac_wininfo(window)->adjustcursor != NULL) + (*mac_wininfo(window)->adjustcursor)(window, mouse, cursrgn); + else { #if TARGET_API_MAC_CARBON GetQDGlobalsArrow(&arrow); SetCursor(&arrow); @@ -719,7 +629,6 @@ static void mac_adjustcursor(RgnHandle cursrgn) { SetCursor(&qd.arrow); CopyRgn(window->visRgn, cursrgn); #endif - break; } } } @@ -749,9 +658,11 @@ void cleanup_exit(int status) exit(status); } -void fatalbox(char *fmt, ...) { +/* This should only kill the current session, not the whole application. */ +void connection_fatal(void *frontend, char *fmt, ...) { va_list ap; Str255 stuff; + Session *s = frontend; va_start(ap, fmt); /* We'd like stuff to be a Pascal string */ @@ -759,34 +670,11 @@ void fatalbox(char *fmt, ...) { va_end(ap); ParamText(stuff, NULL, NULL, NULL); StopAlert(128, NULL); - cleanup_exit(1); -} -void modalfatalbox(char *fmt, ...) { - va_list ap; - Str255 stuff; - - va_start(ap, fmt); - /* We'd like stuff to be a Pascal string */ - stuff[0] = vsprintf((char *)(&stuff[1]), fmt, ap); - va_end(ap); - ParamText(stuff, NULL, NULL, NULL); - StopAlert(128, NULL); - cleanup_exit(1); -} + s->session_closed = TRUE; -/* This should only kill the current session, not the whole application. */ -void connection_fatal(void *fontend, char *fmt, ...) { - va_list ap; - Str255 stuff; - - va_start(ap, fmt); - /* We'd like stuff to be a Pascal string */ - stuff[0] = vsprintf((char *)(&stuff[1]), fmt, ap); - va_end(ap); - ParamText(stuff, NULL, NULL, NULL); - StopAlert(128, NULL); - cleanup_exit(1); + if (s->cfg.close_on_exit == FORCE_ON) + mac_closewindow(s->window); } /* Null SSH agent client -- never finds an agent. */ @@ -797,24 +685,81 @@ int agent_exists(void) return FALSE; } -void agent_query(void *in, int inlen, void **out, int *outlen) +int agent_query(void *in, int inlen, void **out, int *outlen, + void (*callback)(void *, void *, int), void *callback_ctx) { *out = NULL; *outlen = 0; + return 1; } /* Temporary null routines for testing. */ -void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype, - char *keystr, char *fingerprint) +int verify_ssh_host_key(void *frontend, char *host, int port, char *keytype, + char *keystr, char *fingerprint, + void (*callback)(void *ctx, int result), void *ctx) { + Str255 pappname; + Str255 pfingerprint; + Str255 pkeytype; + Session *s = frontend; + int ret, alertret; + + c2pstrcpy(pappname, appname); + c2pstrcpy(pkeytype, keytype); + c2pstrcpy(pfingerprint, fingerprint); + + /* + * The alert shouldn't be modal, it should be movable modal, or + * a sheet in Aqua. Also, PuTTY might be in the background, in + * which case we should use the Notification Manager to wake up + * the user. In any case, we shouldn't hold up processing of + * other connections' data just because this one's waiting for + * the user. + */ + + /* Verify the key against the cache */ + + ret = verify_host_key(host, port, keytype, keystr); + if (ret == 0) { /* success - key matched OK */ + return 1; + } else if (ret == 2) { /* key was different */ + ParamText(pappname, pkeytype, pfingerprint, NULL); + alertret=CautionAlert(wWrong, NULL); + if (alertret == 8) { + /* Cancel */ + return 0; + } else if (alertret == 9) { + /* Connect Just Once */ + return 1; + } else { + /* Update Key */ + store_host_key(host, port, keytype, keystr); + return 1; + } + } else /* ret == 1 */ { /* key was absent */ + ParamText(pkeytype, pfingerprint, pappname, NULL); + alertret=CautionAlert(wAbsent, NULL); + if (alertret == 7) { + /* Cancel */ + return 0; + } else if (alertret == 8) { + /* Connect Just Once */ + return 1; + } else { + /* Update Key */ + store_host_key(host, port, keytype, keystr); + return 1; + } + } } -void askcipher(void *frontend, char *ciphername, int cs) +int askalg(void *frontend, const char *algtype, const char *algname, + void (*callback)(void *ctx, int result), void *ctx) { - + return 0; } void old_keyfile_warning(void) @@ -882,83 +827,50 @@ void platform_get_x11_auth(char *display, int *proto, /* SGT: I have no idea whether Mac X servers need anything here. */ } -Filename filename_from_str(const char *str) +void update_specials_menu(void *frontend) { - Filename ret; - Str255 tmp; + Session *s = frontend; + WindowPtr front; - /* XXX This fails for filenames over 255 characters long. */ - c2pstrcpy(tmp, str); - FSMakeFSSpec(0, 0, tmp, &ret.fss); - return ret; + front = mac_frontwindow(); + if (front != NULL && mac_windowsession(front) == s) + mac_adjustmenus(); } -/* - * Convert a filename to a string for display purposes. - * See pp 2-44--2-46 of IM:Files - * - * XXX static storage considered harmful - */ -const char *filename_to_str(const Filename *fn) -{ - CInfoPBRec pb; - Str255 dirname; - OSErr err; - static char *path = NULL; - char *newpath; - - if (path != NULL) sfree(path); - path = smalloc(fn->fss.name[0]); - p2cstrcpy(path, fn->fss.name); - pb.dirInfo.ioNamePtr = dirname; - pb.dirInfo.ioVRefNum = fn->fss.vRefNum; - pb.dirInfo.ioDrParID = fn->fss.parID; - pb.dirInfo.ioFDirIndex = -1; - do { - pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID; - err = PBGetCatInfoSync(&pb); - - /* XXX Assume not A/UX */ - newpath = smalloc(strlen(path) + dirname[0] + 2); - p2cstrcpy(newpath, dirname); - strcat(newpath, ":"); - strcat(newpath, path); - sfree(path); - path = newpath; - } while (pb.dirInfo.ioDrDirID != fsRtDirID); - return path; -} - -int filename_equal(Filename f1, Filename f2) +void notify_remote_exit(void *frontend) { + Session *s = frontend; + int exitcode; + + if (!s->session_closed && + (exitcode = s->back->exitcode(s->backhandle)) >=0) { + s->session_closed = TRUE; + if (s->cfg.close_on_exit == FORCE_ON || + (s->cfg.close_on_exit == AUTO && exitcode == 0)) { + mac_closewindow(s->window); + return; + } - return f1.fss.vRefNum == f2.fss.vRefNum && - f1.fss.parID == f2.fss.parID && - f1.fss.name[0] == f2.fss.name[0] && - memcmp(f1.fss.name + 1, f2.fss.name + 1, f1.fss.name[0]) == 0; -} + /* The session's dead */ -int filename_is_null(Filename fn) -{ + if (s->ldisc) { + ldisc_free(s->ldisc); + s->ldisc = NULL; + } - return fn.fss.vRefNum == 0 && fn.fss.parID == 0 && fn.fss.name[0] == 0; -} + if (s->back) { + s->back->free(s->backhandle); + s->backhandle = NULL; + s->back = NULL; + update_specials_menu(s); + } -FILE *f_open(Filename fn, char const *mode) -{ - short savevol; - long savedir; - char tmp[256]; - FILE *ret; - - HGetVol(NULL, &savevol, &savedir); - if (HSetVol(NULL, fn.fss.vRefNum, fn.fss.parID) == noErr) { - p2cstrcpy(tmp, fn.fss.name); - ret = fopen(tmp, mode); - } else - ret = NULL; - HSetVol(NULL, savevol, savedir); - return ret; + { + char title[100]; + sprintf(title, "%.70s (inactive)", appname); + set_title(s, title); + } + } } /*