Fix a null-dereference introduced by another mis-fix in r9919.
[sgt/putty] / macosx / osxdlg.m
index 5bc13a4..295b675 100644 (file)
     int hmin = 0;
     int panelht = 0;
 
-    get_sesslist(&sl, TRUE);
-
     ctrlbox = ctrl_new_box();
-    setup_config_box(ctrlbox, &sl, FALSE /*midsession*/, aCfg.protocol,
+    setup_config_box(ctrlbox, FALSE /*midsession*/, aCfg.protocol,
                     0 /* protcfginfo */);
-    unix_setup_config_box(ctrlbox, FALSE /*midsession*/);
+    unix_setup_config_box(ctrlbox, FALSE /*midsession*/, aCfg.protocol);
 
     cfg = aCfg;                               /* structure copy */
 
  * Various special-purpose dialog boxes.
  */
 
-int askappend(void *frontend, Filename filename)
+struct appendstate {
+    void (*callback)(void *ctx, int result);
+    void *ctx;
+};
+
+static void askappend_callback(void *ctx, int result)
+{
+    struct appendstate *state = (struct appendstate *)ctx;
+
+    state->callback(state->ctx, (result == NSAlertFirstButtonReturn ? 2 :
+                                result == NSAlertSecondButtonReturn ? 1 : 0));
+    sfree(state);
+}
+
+int askappend(void *frontend, Filename filename,
+             void (*callback)(void *ctx, int result), void *ctx)
+{
+    static const char msgtemplate[] =
+       "The session log file \"%s\" already exists. "
+       "You can overwrite it with a new session log, "
+       "append your session log to the end of it, "
+       "or disable session logging for this session.";
+
+    char *text;
+    SessionWindow *win = (SessionWindow *)frontend;
+    struct appendstate *state;
+    NSAlert *alert;
+
+    text = dupprintf(msgtemplate, filename.path);
+
+    state = snew(struct appendstate);
+    state->callback = callback;
+    state->ctx = ctx;
+
+    alert = [[NSAlert alloc] init];
+    [alert setInformativeText:[NSString stringWithCString:text]];
+    [alert addButtonWithTitle:@"Overwrite"];
+    [alert addButtonWithTitle:@"Append"];
+    [alert addButtonWithTitle:@"Disable"];
+    [win startAlert:alert withCallback:askappend_callback andCtx:state];
+
+    return -1;
+}
+
+struct algstate {
+    void (*callback)(void *ctx, int result);
+    void *ctx;
+};
+
+static void askalg_callback(void *ctx, int result)
+{
+    struct algstate *state = (struct algstate *)ctx;
+
+    state->callback(state->ctx, result == NSAlertFirstButtonReturn);
+    sfree(state);
+}
+
+int askalg(void *frontend, const char *algtype, const char *algname,
+          void (*callback)(void *ctx, int result), void *ctx)
 {
-    return 0;                         /* FIXME */
+    static const char msg[] =
+       "The first %s supported by the server is "
+       "%s, which is below the configured warning threshold.\n"
+       "Continue with connection?";
+
+    char *text;
+    SessionWindow *win = (SessionWindow *)frontend;
+    struct algstate *state;
+    NSAlert *alert;
+
+    text = dupprintf(msg, algtype, algname);
+
+    state = snew(struct algstate);
+    state->callback = callback;
+    state->ctx = ctx;
+
+    alert = [[NSAlert alloc] init];
+    [alert setInformativeText:[NSString stringWithCString:text]];
+    [alert addButtonWithTitle:@"Yes"];
+    [alert addButtonWithTitle:@"No"];
+    [win startAlert:alert withCallback:askalg_callback andCtx:state];
+
+    return -1;
 }
 
-void askalg(void *frontend, const char *algtype, const char *algname)
+struct hostkeystate {
+    char *host, *keytype, *keystr;
+    int port;
+    void (*callback)(void *ctx, int result);
+    void *ctx;
+};
+
+static void verify_ssh_host_key_callback(void *ctx, int result)
 {
-    fatalbox("Cipher algorithm dialog box not supported yet");
-    return;                           /* FIXME */
+    struct hostkeystate *state = (struct hostkeystate *)ctx;
+
+    if (result == NSAlertThirdButtonReturn)   /* `Accept' */
+       store_host_key(state->host, state->port,
+                      state->keytype, state->keystr);
+    state->callback(state->ctx, result != NSAlertFirstButtonReturn);
+    sfree(state->host);
+    sfree(state->keytype);
+    sfree(state->keystr);
+    sfree(state);
 }
 
-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)
 {
+    static const char absenttxt[] =
+       "The server's host key is not cached. You have no guarantee "
+       "that the server is the computer you think it is.\n"
+       "The server's %s key fingerprint is:\n"
+       "%s\n"
+       "If you trust this host, press \"Accept\" to add the key to "
+       "PuTTY's cache and carry on connecting.\n"
+       "If you want to carry on connecting just once, without "
+       "adding the key to the cache, press \"Connect Once\".\n"
+       "If you do not trust this host, press \"Cancel\" to abandon the "
+       "connection.";
+    static const char wrongtxt[] =
+       "WARNING - POTENTIAL SECURITY BREACH!\n"
+       "The server's host key does not match the one PuTTY has "
+       "cached. This means that either the server administrator "
+       "has changed the host key, or you have actually connected "
+       "to another computer pretending to be the server.\n"
+       "The new %s key fingerprint is:\n"
+       "%s\n"
+       "If you were expecting this change and trust the new key, "
+       "press \"Accept\" to update PuTTY's cache and continue connecting.\n"
+       "If you want to carry on connecting but without updating "
+       "the cache, press \"Connect Once\".\n"
+       "If you want to abandon the connection completely, press "
+       "\"Cancel\" to cancel. Pressing \"Cancel\" is the ONLY guaranteed "
+       "safe choice.";
+
     int ret;
+    char *text;
+    SessionWindow *win = (SessionWindow *)frontend;
+    struct hostkeystate *state;
+    NSAlert *alert;
 
     /*
      * Verify the key.
@@ -328,30 +453,27 @@ void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
     ret = verify_host_key(host, port, keytype, keystr);
 
     if (ret == 0)
-       return;
-
-    /*
-     * FIXME FIXME FIXME. I currently lack any sensible means of
-     * asking the user for a verification non-application-modally,
-     * _or_ any means of closing just this connection if the answer
-     * is no (the Unix and Windows ports just exit() in this
-     * situation since they're one-connection-per-process).
-     * 
-     * What I need to do is to make this function optionally-
-     * asynchronous, much like the interface to agent_query(). It
-     * can either run modally and return a result directly, _or_ it
-     * can kick off a non-modal dialog, return a `please wait'
-     * status, and the dialog can call the backend back when the
-     * result comes in. Also, in either case, the aye/nay result
-     * wants to be passed to the backend so that it can tear down
-     * the connection if the answer was nay.
-     * 
-     * For the moment, I simply bomb out if we have an unrecognised
-     * host key. This makes this port safe but not very useful: you
-     * can only use it at all if you already have a host key cache
-     * set up by running the Unix port.
-     */
-    fatalbox("Host key dialog box not supported yet");
+       return 1;
+
+    text = dupprintf((ret == 2 ? wrongtxt : absenttxt), keytype, fingerprint);
+
+    state = snew(struct hostkeystate);
+    state->callback = callback;
+    state->ctx = ctx;
+    state->host = dupstr(host);
+    state->port = port;
+    state->keytype = dupstr(keytype);
+    state->keystr = dupstr(keystr);
+
+    alert = [[NSAlert alloc] init];
+    [alert setInformativeText:[NSString stringWithCString:text]];
+    [alert addButtonWithTitle:@"Cancel"];
+    [alert addButtonWithTitle:@"Connect Once"];
+    [alert addButtonWithTitle:@"Accept"];
+    [win startAlert:alert withCallback:verify_ssh_host_key_callback
+     andCtx:state];
+
+    return -1;
 }
 
 void old_keyfile_warning(void)
@@ -361,7 +483,27 @@ void old_keyfile_warning(void)
      */
 }
 
-void about_box(void *window)
+static void connection_fatal_callback(void *ctx, int result)
+{
+    SessionWindow *win = (SessionWindow *)ctx;
+
+    [win endSession:FALSE];
+}
+
+void connection_fatal(void *frontend, char *p, ...)
 {
-    /* FIXME */
+    SessionWindow *win = (SessionWindow *)frontend;
+    va_list ap;
+    char *msg;
+    NSAlert *alert;
+
+    va_start(ap, p);
+    msg = dupvprintf(p, ap);
+    va_end(ap);
+
+    alert = [[NSAlert alloc] init];
+    [alert setInformativeText:[NSString stringWithCString:msg]];
+    [alert addButtonWithTitle:@"Proceed"];
+    [win startAlert:alert withCallback:connection_fatal_callback
+     andCtx:win];
 }