Revamp SSH authentication code so that user interaction is more
[u/mdw/putty] / unix / gtkwin.c
index 1b0ba4a..6193a04 100644 (file)
@@ -64,7 +64,7 @@ struct gui_data {
        int is_wide;
     } fontinfo[4];
     int xpos, ypos, gotpos, gravity;
-    GdkCursor *rawcursor, *textcursor, *blankcursor, *currcursor;
+    GdkCursor *rawcursor, *textcursor, *blankcursor, *waitcursor, *currcursor;
     GdkColor cols[NALLCOLOURS];
     GdkColormap *colmap;
     wchar_t *pastein_data;
@@ -76,6 +76,7 @@ struct gui_data {
     int width, height;
     int ignore_sbar;
     int mouseptr_visible;
+    int busy_status;
     guint term_paste_idle_id;
     int alt_keycode;
     int alt_digits;
@@ -94,6 +95,7 @@ struct gui_data {
     char *progname, **gtkargvstart;
     int ngtkargs;
     guint32 input_event_time; /* Timestamp of the most recent input event. */
+    int reconfiguring;
 };
 
 struct draw_ctx {
@@ -175,12 +177,34 @@ void ldisc_update(void *frontend, int echo, int edit)
      */
 }
 
+char *get_ttymode(void *frontend, const char *mode)
+{
+    struct gui_data *inst = (struct gui_data *)frontend;
+    return term_get_ttymode(inst->term, mode);
+}
+
 int from_backend(void *frontend, int is_stderr, const char *data, int len)
 {
     struct gui_data *inst = (struct gui_data *)frontend;
     return term_data(inst->term, is_stderr, data, len);
 }
 
+int from_backend_untrusted(void *frontend, const char *data, int len)
+{
+    struct gui_data *inst = (struct gui_data *)frontend;
+    return term_data_untrusted(inst->term, data, len);
+}
+
+int get_userpass_input(prompts_t *p, unsigned char *in, int inlen)
+{
+    struct gui_data *inst = (struct gui_data *)p->frontend;
+    int ret;
+    ret = cmdline_get_passwd_input(p, in, inlen);
+    if (ret == -1)
+       ret = term_get_userpass_input(inst->term, p, in, inlen);
+    return ret;
+}
+
 void logevent(void *frontend, const char *string)
 {
     struct gui_data *inst = (struct gui_data *)frontend;
@@ -372,15 +396,34 @@ gint delete_window(GtkWidget *widget, GdkEvent *event, gpointer data)
     return FALSE;
 }
 
+static void update_mouseptr(struct gui_data *inst)
+{
+    switch (inst->busy_status) {
+      case BUSY_NOT:
+       if (!inst->mouseptr_visible) {
+           gdk_window_set_cursor(inst->area->window, inst->blankcursor);
+       } else if (send_raw_mouse) {
+           gdk_window_set_cursor(inst->area->window, inst->rawcursor);
+       } else {
+           gdk_window_set_cursor(inst->area->window, inst->textcursor);
+       }
+       break;
+      case BUSY_WAITING:    /* XXX can we do better? */
+      case BUSY_CPU:
+       /* We always display these cursors. */
+       gdk_window_set_cursor(inst->area->window, inst->waitcursor);
+       break;
+      default:
+       assert(0);
+    }
+}
+
 static void show_mouseptr(struct gui_data *inst, int show)
 {
     if (!inst->cfg.hide_mouseptr)
        show = 1;
-    if (show)
-       gdk_window_set_cursor(inst->area->window, inst->currcursor);
-    else
-       gdk_window_set_cursor(inst->area->window, inst->blankcursor);
     inst->mouseptr_visible = show;
+    update_mouseptr(inst);
 }
 
 void draw_backing_rect(struct gui_data *inst)
@@ -1149,7 +1192,7 @@ void notify_remote_exit(void *frontend)
        inst->exited = TRUE;
        if (inst->cfg.close_on_exit == FORCE_ON ||
            (inst->cfg.close_on_exit == AUTO && exitcode == 0))
-           exit(0);                   /* just go. */
+           gtk_main_quit();           /* just go */
        if (inst->ldisc) {
            ldisc_free(inst->ldisc);
            inst->ldisc = NULL;
@@ -1227,6 +1270,13 @@ gint focus_event(GtkWidget *widget, GdkEventFocus *event, gpointer data)
     return FALSE;
 }
 
+void set_busy_status(void *frontend, int status)
+{
+    struct gui_data *inst = (struct gui_data *)frontend;
+    inst->busy_status = status;
+    update_mouseptr(inst);
+}
+
 /*
  * set or clear the "raw mouse message" mode
  */
@@ -1235,11 +1285,7 @@ void set_raw_mouse_mode(void *frontend, int activate)
     struct gui_data *inst = (struct gui_data *)frontend;
     activate = activate && !inst->cfg.no_mouse_rep;
     send_raw_mouse = activate;
-    if (send_raw_mouse)
-       inst->currcursor = inst->rawcursor;
-    else
-       inst->currcursor = inst->textcursor;
-    show_mouseptr(inst, inst->mouseptr_visible);
+    update_mouseptr(inst);
 }
 
 void request_resize(void *frontend, int w, int h)
@@ -1322,7 +1368,7 @@ static void real_palette_set(struct gui_data *inst, int n, int r, int g, int b)
 
     gdk_colormap_free_colors(inst->colmap, inst->cols + n, 1);
     gdk_colormap_alloc_colors(inst->colmap, inst->cols + n, 1,
-                             FALSE, FALSE, success);
+                             FALSE, TRUE, success);
     if (!success[0])
        g_error("%s: couldn't allocate colour %d (#%02x%02x%02x)\n", appname,
                n, r, g, b);
@@ -1377,19 +1423,19 @@ void palette_reset(void *frontend)
     for (i = 0; i < NEXTCOLOURS; i++) {
        if (i < 216) {
            int r = i / 36, g = (i / 6) % 6, b = i % 6;
-           inst->cols[i+16].red = r * 0x3333;
-           inst->cols[i+16].green = g * 0x3333;
-           inst->cols[i+16].blue = b * 0x3333;
+           inst->cols[i+16].red = r ? r * 0x2828 + 0x3737 : 0;
+           inst->cols[i+16].green = g ? g * 0x2828 + 0x3737 : 0;
+           inst->cols[i+16].blue = b ? b + 0x2828 + 0x3737 : 0;
        } else {
            int shade = i - 216;
-           shade = (shade + 1) * 0xFFFF / (NEXTCOLOURS - 216 + 1);
+           shade = shade * 0x0a0a + 0x0808;
            inst->cols[i+16].red = inst->cols[i+16].green =
                inst->cols[i+16].blue = shade;
        }
     }
 
     gdk_colormap_alloc_colors(inst->colmap, inst->cols, NALLCOLOURS,
-                             FALSE, FALSE, success);
+                             FALSE, TRUE, success);
     for (i = 0; i < NALLCOLOURS; i++) {
        if (!success[i])
            g_error("%s: couldn't allocate colour %d (#%02x%02x%02x)\n",
@@ -1855,6 +1901,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
     GdkGC *gc = dctx->gc;
     int ncombining, combining;
     int nfg, nbg, t, fontid, shadow, rlen, widefactor;
+    int monochrome = gtk_widget_get_visual(inst->area)->depth == 1;
 
     if (attr & TATTR_COMBINING) {
        ncombining = len;
@@ -1862,9 +1909,9 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
     } else
        ncombining = 1;
 
-    nfg = ((attr & ATTR_FGMASK) >> ATTR_FGSHIFT);
-    nbg = ((attr & ATTR_BGMASK) >> ATTR_BGSHIFT);
-    if (attr & ATTR_REVERSE) {
+    nfg = ((monochrome ? ATTR_DEFFG : (attr & ATTR_FGMASK)) >> ATTR_FGSHIFT);
+    nbg = ((monochrome ? ATTR_DEFBG : (attr & ATTR_BGMASK)) >> ATTR_BGSHIFT);
+    if (!!(attr & ATTR_REVERSE) ^ (monochrome && (attr & TATTR_ACTCURS))) {
        t = nfg;
        nfg = nbg;
        nbg = t;
@@ -1877,7 +1924,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
        if (nbg < 16) nbg |= 8;
        else if (nbg >= 256) nbg |= 1;
     }
-    if (attr & TATTR_ACTCURS) {
+    if ((attr & TATTR_ACTCURS) && !monochrome) {
        nfg = 260;
        nbg = 261;
     }
@@ -2537,7 +2584,11 @@ int do_cmdline(int argc, char **argv, int do_everything,
        } else if(!strcmp(p, "-help") || !strcmp(p, "--help")) {
            help(stdout);
            exit(0);
-           
+
+        } else if (!strcmp(p, "-pgpfp")) {
+            pgp_fingerprints();
+            exit(1);
+
        } else if(p[0] != '-' && (!do_everything ||
                                   process_nonoption_arg(p, cfg))) {
             /* do nothing */
@@ -2855,6 +2906,11 @@ void change_settings_menuitem(GtkMenuItem *item, gpointer data)
 
     assert(lenof(ww) == NCFGCOLOURS);
 
+    if (inst->reconfiguring)
+      return;
+    else
+      inst->reconfiguring = TRUE;
+
     cfg2 = inst->cfg;                  /* structure copy */
 
     if (do_config_box(title, &cfg2, 1,
@@ -2972,6 +3028,7 @@ void change_settings_menuitem(GtkMenuItem *item, gpointer data)
        gtk_widget_queue_draw(inst->area);
     }
     sfree(title);
+    inst->reconfiguring = FALSE;
 }
 
 void fork_and_exec_self(struct gui_data *inst, int fd_to_close, ...)
@@ -3192,6 +3249,33 @@ void saved_session_freedata(GtkMenuItem *item, gpointer data)
     sfree(str);
 }
 
+static void update_savedsess_menu(GtkMenuItem *menuitem, gpointer data)
+{
+    struct gui_data *inst = (struct gui_data *)data;
+    struct sesslist sesslist;
+    int i;
+
+    gtk_container_foreach(GTK_CONTAINER(inst->sessionsmenu),
+                         (GtkCallback)gtk_widget_destroy, NULL);
+
+    get_sesslist(&sesslist, TRUE);
+    for (i = 1; i < sesslist.nsessions; i++) {
+       GtkWidget *menuitem =
+           gtk_menu_item_new_with_label(sesslist.sessions[i]);
+       gtk_container_add(GTK_CONTAINER(inst->sessionsmenu), menuitem);
+       gtk_widget_show(menuitem);
+       gtk_object_set_data(GTK_OBJECT(menuitem), "user-data",
+                           dupstr(sesslist.sessions[i]));
+       gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
+                          GTK_SIGNAL_FUNC(saved_session_menuitem),
+                          inst);
+       gtk_signal_connect(GTK_OBJECT(menuitem), "destroy",
+                          GTK_SIGNAL_FUNC(saved_session_freedata),
+                          inst);
+    }
+    get_sesslist(&sesslist, FALSE); /* free up */
+}
+
 void update_specials_menu(void *frontend)
 {
     struct gui_data *inst = (struct gui_data *)frontend;
@@ -3310,6 +3394,7 @@ int pt_main(int argc, char **argv)
     inst = snew(struct gui_data);
     memset(inst, 0, sizeof(*inst));
     inst->alt_keycode = -1;            /* this one needs _not_ to be zero */
+    inst->busy_status = BUSY_NOT;
 
     /* defer any child exit handling until we're ready to deal with
      * it */
@@ -3470,28 +3555,10 @@ int pt_main(int argc, char **argv)
        gtk_widget_hide(inst->restartitem);
         MKMENUITEM("Duplicate Session", dup_session_menuitem);
        if (saved_sessions) {
-           struct sesslist sesslist;
-           int i;
-
            inst->sessionsmenu = gtk_menu_new();
-
-           get_sesslist(&sesslist, TRUE);
-           for (i = 1; i < sesslist.nsessions; i++) {
-               menuitem = gtk_menu_item_new_with_label(sesslist.sessions[i]);
-               gtk_container_add(GTK_CONTAINER(inst->sessionsmenu), menuitem);
-               gtk_widget_show(menuitem);
-               gtk_object_set_data(GTK_OBJECT(menuitem), "user-data",
-                                   dupstr(sesslist.sessions[i]));
-               gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
-                                  GTK_SIGNAL_FUNC(saved_session_menuitem),
-                                  inst);
-               gtk_signal_connect(GTK_OBJECT(menuitem), "destroy",
-                                  GTK_SIGNAL_FUNC(saved_session_freedata),
-                                  inst);
-           }
-           get_sesslist(&sesslist, FALSE);
-
-           MKMENUITEM("Saved Sessions", NULL);
+           /* sessionsmenu will be updated when it's invoked */
+           /* XXX is this the right way to do dynamic menus in Gtk? */
+           MKMENUITEM("Saved Sessions", update_savedsess_menu);
            gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem),
                                      inst->sessionsmenu);
        }
@@ -3520,6 +3587,7 @@ int pt_main(int argc, char **argv)
 
     inst->textcursor = make_mouse_ptr(inst, GDK_XTERM);
     inst->rawcursor = make_mouse_ptr(inst, GDK_LEFT_PTR);
+    inst->waitcursor = make_mouse_ptr(inst, GDK_WATCH);
     inst->blankcursor = make_mouse_ptr(inst, -1);
     make_mouse_ptr(inst, -2);         /* clean up cursor font */
     inst->currcursor = inst->textcursor;