+ dlg_init(&dp);
+
+ for (index = 0; index < lenof(scs.sc); index++) {
+ scs.sc[index].action = SHORTCUT_EMPTY;
+ }
+
+ ctrlbox = ctrl_new_box();
+
+ ncols = 0;
+ va_start(ap, minwid);
+ while (va_arg(ap, char *) != NULL) {
+ ncols++;
+ (void) va_arg(ap, int); /* shortcut */
+ (void) va_arg(ap, int); /* normal/default/cancel */
+ (void) va_arg(ap, int); /* end value */
+ }
+ va_end(ap);
+
+ s0 = ctrl_getset(ctrlbox, "", "", "");
+ c = ctrl_columns(s0, 2, 50, 50);
+ c->columns.ncols = s0->ncolumns = ncols;
+ c->columns.percentages = sresize(c->columns.percentages, ncols, int);
+ for (index = 0; index < ncols; index++)
+ c->columns.percentages[index] = (index+1)*100/ncols - index*100/ncols;
+ va_start(ap, minwid);
+ index = 0;
+ while (1) {
+ char *title = va_arg(ap, char *);
+ int shortcut, type, value;
+ if (title == NULL)
+ break;
+ shortcut = va_arg(ap, int);
+ type = va_arg(ap, int);
+ value = va_arg(ap, int);
+ c = ctrl_pushbutton(s0, title, shortcut, HELPCTX(no_help),
+ messagebox_handler, I(value));
+ c->generic.column = index++;
+ if (type > 0)
+ c->button.isdefault = TRUE;
+ else if (type < 0)
+ c->button.iscancel = TRUE;
+ }
+ va_end(ap);
+
+ s1 = ctrl_getset(ctrlbox, "x", "", "");
+ ctrl_text(s1, msg, HELPCTX(no_help));
+
+ window = gtk_dialog_new();
+ gtk_window_set_title(GTK_WINDOW(window), title);
+ w0 = layout_ctrls(&dp, &scs, s0, GTK_WINDOW(window));
+ set_dialog_action_area(GTK_DIALOG(window), w0);
+ gtk_widget_show(w0);
+ w1 = layout_ctrls(&dp, &scs, s1, GTK_WINDOW(window));
+ gtk_container_set_border_width(GTK_CONTAINER(w1), 10);
+ gtk_widget_set_usize(w1, minwid+20, -1);
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->vbox),
+ w1, TRUE, TRUE, 0);
+ gtk_widget_show(w1);
+
+ dp.shortcuts = &scs;
+ dp.lastfocus = NULL;
+ dp.retval = 0;
+ dp.window = window;
+
+ gtk_window_set_modal(GTK_WINDOW(window), TRUE);
+ if (parentwin) {
+ set_transient_window_pos(parentwin, window);
+ gtk_window_set_transient_for(GTK_WINDOW(window),
+ GTK_WINDOW(parentwin));
+ } else
+ gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
+ gtk_widget_show(window);
+
+ gtk_signal_connect(GTK_OBJECT(window), "destroy",
+ GTK_SIGNAL_FUNC(window_destroy), NULL);
+ gtk_signal_connect(GTK_OBJECT(window), "key_press_event",
+ GTK_SIGNAL_FUNC(win_key_press), &dp);
+
+ gtk_main();
+
+ dlg_cleanup(&dp);
+ ctrl_free_box(ctrlbox);
+
+ return dp.retval;
+}
+
+static int string_width(char *text)
+{
+ GtkWidget *label = gtk_label_new(text);
+ GtkRequisition req;
+ gtk_widget_size_request(label, &req);
+ gtk_object_sink(GTK_OBJECT(label));
+ return req.width;
+}
+
+int reallyclose(void *frontend)
+{
+ char *title = dupcat(appname, " Exit Confirmation", NULL);
+ int ret = messagebox(GTK_WIDGET(get_window(frontend)),
+ title, "Are you sure you want to close this session?",
+ string_width("Most of the width of the above text"),
+ "Yes", 'y', +1, 1,
+ "No", 'n', -1, 0,
+ NULL);
+ sfree(title);
+ return ret;
+}
+
+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.";
+ char *text;
+ int ret;
+
+ /*
+ * Verify the key.
+ */
+ ret = verify_host_key(host, port, keytype, keystr);
+
+ if (ret == 0) /* success - key matched OK */
+ return 1;