Rationalise access to, and content of, backends[] array.
[sgt/putty] / mac / mac.c
index a9a327f..2536206 100644 (file)
--- a/mac/mac.c
+++ b/mac/mac.c
@@ -1,4 +1,4 @@
-/* $Id: mac.c,v 1.52 2003/02/27 23:34:59 ben Exp $ */
+/* $Id$ */
 /*
  * Copyright (c) 1999, 2003 Ben Harris
  * All rights reserved.
@@ -31,6 +31,7 @@
 #include <MacTypes.h>
 #include <AEDataModel.h>
 #include <AppleEvents.h>
+#include <Controls.h>
 #include <Quickdraw.h>
 #include <Fonts.h>
 #include <MacWindows.h>
@@ -61,6 +62,7 @@
 #include "macresid.h"
 #include "putty.h"
 #include "ssh.h"
+#include "terminal.h"
 #include "mac.h"
 
 Session *sesslist;
@@ -68,6 +70,8 @@ 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);
@@ -192,8 +196,11 @@ static void mac_startup(void) {
        fatalbox("Unable to create menu bar.");
     SetMenuBar(menuBar);
     AppendResMenu(GetMenuHandle(mApple), 'DRVR');
-    if (mac_gestalts.menuattr & gestaltMenuMgrAquaLayoutMask)
+    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();
@@ -203,13 +210,10 @@ static void mac_startup(void) {
     default_protocol = be_default_protocol;
     /* Find the appropriate default port. */
     {
-       int i;
+       Backend *b = backend_from_proto(default_protocol);
        default_port = 0; /* illegal */
-       for (i = 0; backends[i].backend != NULL; i++)
-           if (backends[i].protocol == default_protocol) {
-               default_port = backends[i].backend->default_port;
-               break;
-           }
+       if (b)
+           default_port = b->default_port;
     }
     flags = FLAG_INTERACTIVE;
 
@@ -238,22 +242,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);
 }
@@ -439,6 +469,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;
@@ -534,6 +567,7 @@ static void mac_adjustmenus(void) {
     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);
@@ -622,9 +656,10 @@ void cleanup_exit(int status)
 }
 
 /* This should only kill the current session, not the whole application. */
-void connection_fatal(void *fontend, char *fmt, ...) {
+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 */
@@ -632,7 +667,11 @@ void connection_fatal(void *fontend, char *fmt, ...) {
     va_end(ap);
     ParamText(stuff, NULL, NULL, NULL);
     StopAlert(128, NULL);
-    cleanup_exit(1);
+
+    s->session_closed = TRUE;
+
+    if (s->cfg.close_on_exit == FORCE_ON)
+       mac_closewindow(s->window);
 }
 
 /* Null SSH agent client -- never finds an agent. */
@@ -643,24 +682,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)
@@ -728,6 +824,52 @@ void platform_get_x11_auth(char *display, int *proto,
     /* SGT: I have no idea whether Mac X servers need anything here. */
 }
 
+void update_specials_menu(void *frontend)
+{
+    Session *s = frontend;
+    WindowPtr front;
+
+    front = mac_frontwindow();
+    if (front != NULL && mac_windowsession(front) == s)
+       mac_adjustmenus();
+}
+
+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;
+       }
+
+       /* The session's dead */
+
+       if (s->ldisc) {
+           ldisc_free(s->ldisc);
+           s->ldisc = NULL;
+       }
+
+       if (s->back) {
+           s->back->free(s->backhandle);
+           s->backhandle = NULL;
+           s->back = NULL;
+           update_specials_menu(s);
+       }
+
+       {
+           char title[100];
+           sprintf(title, "%.70s (inactive)", appname);
+           set_title(s, title);
+       }
+    }
+}
+
 /*
  * Local Variables:
  * c-file-style: "simon"