#if 0 /* # A KLUDGE!! to lets this know whether we're (probably) compiling for N770... test -f /etc/init.d/maemo-launcher \ && XD="-DM4EMO=2 `pkg-config --cflags --libs libosso hildon-libs`" \ || XD= TRG=`basename $0 .c` DATE=`date` [ x"$1" = xclean ] && { set -x; exec rm -f $TRG; } [ x"$1" = x ] && set -- -s -O2 WARN="-Wall -Wstrict-prototypes -pedantic -Wno-long-long" WARN="$WARN -Wcast-align -Wpointer-arith " # -Wfloat-equal #-Werror WARN="$WARN -W -Wwrite-strings -Wcast-qual -Wshadow" # -Wconversion set -x; exec ${CC:-gcc} -Wall "$@" -o $TRG $0 -DBUILDDATE="\"$DATE\"" $XD\ `pkg-config --cflags --libs gtk+-2.0` -lutil #*/ #endif /* * $Id: revsh-tunnel-gui.c 1143 2006-11-23 21:07:13Z too $ * * Author: Tomi Ollila -- too ät iki.fi * * Copyright (c) 2006 Tomi Ollila * All rights reserved * * Created: Thu Jan 12 21:47:26 EET 2006 too * Last modified: Thu Nov 23 23:01:34 EET 2006 too */ #define PRJ_VER "1.93" /* Note: // is good trick to outcomment FIXME-stuff as (gnu) c compiler _ warns about it */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if 0 /* set 1 to force m4em0 for some tests... */ #ifndef M4EMO #define M4EMO 1 #endif #endif #if M4EMO > 1 #include #include #include HildonProgram * G_hildonprogram = NULL; #endif #define null ((void *)0) typedef enum { false = 0, true = 1 } bool; typedef char bool8; #if 1 #define d2(x) do { printf_to_buffer x; printf_to_buffer("\n"); } while (0) #define d1(x) do { printf x; printf("\n"); } while (0) #define d0(x) do {} while (0) #else #define d2(x) do {} while (0) #define d1(x) do {} while (0) #define d0(x) do {} while (0) #endif #if M4EMO > 1 /* #define SSH_COMMAND "/usr/bin/dbclient" */ #define SSH_COMMAND "dbclient" #else #define SSH_COMMAND "ssh" #endif #if (__GNUC__ >= 4) #define GCCATTR_SENTINEL __attribute ((sentinel)) #else #define GCCATTR_SENTINEL #endif #if (__GNUC__ >= 3) #define GCCATTR_NORETURN __attribute ((noreturn)) #define GCCATTR_UNUSED __attribute ((unused)) #define GCCATTR_CONST __attribute ((const)) #define S2U(v, t, i, o) \ __builtin_choose_expr (__builtin_types_compatible_p (typeof (v), t i), \ ((unsigned t o)(v)), (void)0) #define U2S(v, t, i, o) \ __builtin_choose_expr (__builtin_types_compatible_p \ (typeof (v), unsigned t o), /**/ ((t o)(v)), (void)0) #else #define GCCATTR_NORETURN #define GCCATTR_UNUSED #define GCCATTR_CONST #define S2U(v, t, i, o) #define U2S(v, t, i, o) #endif #define UU GCCATTR_UNUSED /* convenience macro */ /* A set of GTK Widget wrappers that are suitable enough for this program. When this code is cut/pasted elsewhere the code is adjusted to fit that project. Note that not much has been done to make the wrappers have consistent arguments -- some functionality is hardcoded in one wrapper where other takes same thing as argument. */ GtkWidget * aWindow(const char * title, gboolean (*delete_cb)(), gpointer deletedata, int borderwidth, bool resizable, bool show, GtkWidget * child) { GtkWidget * window; #if M4EMO > 1 if (G_hildonprogram) return NULL; /* XXX this line plus no checks below */ G_hildonprogram = HILDON_PROGRAM(hildon_program_get_instance()); g_set_application_name(title); window = GTK_WIDGET(hildon_window_new()); hildon_program_add_window(G_hildonprogram, HILDON_WINDOW(window)); #else window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), title); #endif g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(delete_cb), deletedata); #if 0 g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(delete_cb), ...); #endif #if ! M4EMO gtk_container_set_border_width (GTK_CONTAINER (window), borderwidth); #endif gtk_container_add(GTK_CONTAINER(window), child); #if ! M4EMO gtk_window_set_resizable(GTK_WINDOW(window), resizable); #endif #if 0 gtk_widget_set_size_request(window, 400, 300); #endif if (show) gtk_widget_show_all(window); return window; } GtkBox * _aBox(bool hbox, gboolean homogeneous, gint spacing, va_list ap) { GtkBox * box; GtkWidget * child; if (hbox) box = GTK_BOX(gtk_hbox_new(homogeneous, spacing)); else box = GTK_BOX(gtk_vbox_new(homogeneous, spacing)); while ((child = va_arg(ap, GtkWidget *)) != null) { gboolean expand = va_arg(ap, gboolean); gboolean fill = va_arg(ap, gboolean); guint padding = va_arg(ap, guint); d0(("%p\n", child)); gtk_box_pack_start(box, child, expand, fill, padding); } return box; } GtkWidget * aHBox(gboolean homogeneous, gint spacing, ...) GCCATTR_SENTINEL; GtkWidget * aHBox(gboolean homogeneous, gint spacing, ...) { GtkBox * hbox; va_list ap; va_start(ap, spacing); hbox = _aBox(true, homogeneous, spacing, ap); va_end(ap); return GTK_WIDGET(hbox); } GtkWidget * aVBox(gboolean homogeneous, gint spacing, ...) GCCATTR_SENTINEL; GtkWidget * aVBox(gboolean homogeneous, gint spacing, ...) { GtkBox * vbox; va_list ap; va_start(ap, spacing); vbox = _aBox(false, homogeneous, spacing, ap); va_end(ap); return GTK_WIDGET(vbox); } GtkWidget * _aButtonBox(bool hbbox, GtkWidget * child, va_list ap) { GtkWidget * bbox; if (hbbox) bbox = GTK_WIDGET(gtk_hbutton_box_new()); else bbox = GTK_WIDGET(gtk_vbutton_box_new()); while (child) { gtk_container_add(GTK_CONTAINER(bbox), child); child = va_arg(ap, GtkWidget *); } return bbox; } GtkWidget * aHButtonBox(GtkWidget * child, ...) GCCATTR_SENTINEL; GtkWidget * aHButtonBox(GtkWidget * child, ...) { GtkWidget * hbbox; va_list ap; va_start(ap, child); hbbox = _aButtonBox(true, child, ap); va_end(ap); return hbbox; } #if 000 GtkWidget * aTable(int cols, bool homogeneous, ...) { va_list ap; GtkTable * table = GTK_TABLE(gtk_table_new(1, cols, homogeneous)); GtkWidget * widget; int r, c; va_start(ap, homogeneous); widget = va_arg(ap, GtkWidget *); for (r = 0; widget; r++) { gtk_table_resize(table, r+1, cols); for (c = 0; c < cols; c++) { gtk_table_attach(table, widget, c, c+1, r, r+1, GTK_FILL | GTK_EXPAND, 0, 0, 2); widget = va_arg(ap, GtkWidget *); } } return GTK_WIDGET(table); } #endif GtkWidget * aTable(int cols, bool homogeneous, ...) GCCATTR_SENTINEL; GtkWidget * aTable(int cols, bool homogeneous, ...) { va_list ap; GtkTable * table = GTK_TABLE(gtk_table_new(1, cols, homogeneous)); GtkWidget * widget; int r, c, w; va_start(ap, homogeneous); widget = va_arg(ap, GtkWidget *); for (r = 0; widget; r++) { gtk_table_resize(table, r+1, cols); for (c = 0; c < cols; c+= w) { w = va_arg(ap, int); gtk_table_attach(table, widget, c, c+w, r, r+1, GTK_FILL | GTK_EXPAND, 0, 0, 2); widget = va_arg(ap, GtkWidget *); } } return GTK_WIDGET(table); } GtkWidget * aLabel(const char * label) { return gtk_label_new(label); } GtkWidget * anEntry(const char * text, int width /*, bool visible*/) { GtkEntry * entry = GTK_ENTRY(gtk_entry_new()); gtk_entry_set_width_chars(entry, width); if (text) gtk_entry_set_text(entry, text); #if M4EMO g_object_set(G_OBJECT(entry), "autocap", false, null); #endif /*gtk_entry_set_visibility(entry, visible); */ return GTK_WIDGET(entry); } GtkWidget * aButton(const char * text, void (*clickmethod)(void), gpointer clickdata) { GtkWidget * button = GTK_WIDGET(gtk_button_new_with_label(text)); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(clickmethod), clickdata); return button; } GtkWidget * anExpander(const char * text, GtkWidget * child) { GtkWidget * expander = gtk_expander_new(text); gtk_container_add(GTK_CONTAINER(expander), child); return expander; } #if 0 GtkWidget * aFrame(const char * text, GtkWidget * child) { GtkWidget * frame = gtk_frame_new(text); gtk_widget_set_size_request(frame, 50, 250); gtk_container_add(GTK_CONTAINER(frame), child); return frame; } #endif GtkWidget * aScrolledWindow(GtkWidget * child) { GtkWidget * swindow = gtk_scrolled_window_new(null, null); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_container_add(GTK_CONTAINER(swindow), child); return swindow; } GtkWidget * aTextView(GtkTextBuffer * child) { GtkWidget * textview = gtk_text_view_new_with_buffer(GTK_TEXT_BUFFER(child)); gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(textview), true); gtk_text_view_set_left_margin(GTK_TEXT_VIEW(textview), 3); gtk_text_view_set_pixels_above_lines(GTK_TEXT_VIEW(textview), 2); gtk_text_view_set_pixels_below_lines(GTK_TEXT_VIEW(textview), 2); gtk_text_view_set_editable(GTK_TEXT_VIEW(textview), false); gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(textview), GTK_WRAP_CHAR); /* gtk_widget_set_size_request(textview, 500, 250); */ return textview; } GtkTextBuffer * aTextBuffer(void) { GtkTextBuffer * textbuffer = gtk_text_buffer_new(null); return textbuffer; } GtkWidget * aListView(void (*selchanged_cb)(), int num_cols, ...) { GtkTreeSelection * sel; GtkListStore * store; // always initialized when used. GtkWidget * view; va_list ap; GType xxx[8]; int i, j; char * s; if (num_cols > sizeof xxx / sizeof xxx[0]) num_cols = sizeof xxx / sizeof xxx[0]; view = null; while (true) { va_start(ap, num_cols); for (i = 0; i < num_cols; i++) { j = xxx[i] = va_arg(ap, GType); switch (j) { case G_TYPE_STRING: s = va_arg(ap, char *); if (view) gtk_tree_view_insert_column_with_attributes /* ( */ (GTK_TREE_VIEW (view), -1, s, gtk_cell_renderer_text_new(), "text", i, NULL); break; default: abort(); /* FIXME */ }} va_end(ap); if (view) break; store = gtk_list_store_newv(num_cols, xxx); view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); } sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE); g_signal_connect(sel, "changed", G_CALLBACK(selchanged_cb), store); return view; } /* ----------- */ gboolean main_window_delete_event(void * w UU, void * e UU, void * rvp) { *(int*)rvp = 0; gtk_main_quit(); return false; } const char * getusername(unsigned int maxlen) { struct passwd * pw = getpwuid(getuid()); if (pw == NULL) return "error-notfound!"; if (strlen(pw->pw_name) > maxlen) return "error-toolong!"; return pw->pw_name; } /* ----------- */ #if 0 static void movefd(int a, int b) { if (a != b) { dup2(a, b); close(a); } } #endif int run_secure_shell(int * pid, char * ident, char * user, char * where) { int tty, pty, i; struct winsize ws; d0(("run_secure_shell(ptr = %s, len = %d)", ptr, len)); ws.ws_col = 40; ws.ws_row = 10; ws.ws_xpixel = ws.ws_ypixel = 0; if (openpty(&pty, &tty, null, null, &ws) < 0) { /* FIXME */ return -1; } d0((" pty fd: %d, tty fd: %d" pty, tty, ws.ws_row, ws.ws_col)); switch ( (*pid = fork()) ) { case 0: /* child */ close(pty); #if 1 login_tty(tty); #else /* disconnect from controlling tty */ close(0); close(1); close(2); setsid(); /* well, setsid() does more */ /* make tty our controlling tty */ ioctl(tty, TIOCSCTTY, null); movefd(tty, 0); dup2(0, 1); dup2(0, 2); #endif for(i = 3; i < 8; i++) close(i); /* close X fd... */ printf("$ revsh -l %s " SSH_COMMAND " -l %s %s\n", ident, user, where); fflush(stdout); execlp("revsh", "revsh", "-l", ident, SSH_COMMAND, "-l", user, where, null); printf("* Can not execute revsh ...: %s\n", strerror(errno)); _exit(1); case -1: close(pty); pty = -1; /* FIXME */ break; default: #if 0 set_close_on_exec(pty); /* FIXME actually not necessary here */ set_nonblocking(pty); #endif break; } /* here in cases above: -1 and default */ close(tty); return pty; } /* ----------- */ struct { GtkWidget * ident; GtkWidget * remote; GtkWidget * user; GtkWidget * swindow; GtkWidget * tview; GtkWidget * lview; GtkWidget * b1, *b2; GtkTextBuffer * buffer; unsigned char buffer_last_char_written; unsigned char connect_state; bool8 buffer_scroll_activated; unsigned char nextsig; int revsh_pid; int revsh_pty; GIOChannel * iochannel; #if M4EMO GtkWidget * tie; #endif } G; void G_init(void) { memset (&G, 0, sizeof G); G.revsh_pty = -1; G.nextsig = 15; } /* ------ */ void add_to_listview(const char * ident, const char * remote,const char * user) { GtkTreeModel * model; GtkTreeIter newrow; model = gtk_tree_view_get_model(GTK_TREE_VIEW(G.lview)); gtk_list_store_append(GTK_LIST_STORE(model), &newrow); gtk_list_store_set(GTK_LIST_STORE(model), &newrow, 0, ident, 1, remote, 2, user, -1); } FILE * open_listview_file(bool wrait) { char fname[512]; char * bnp; FILE * fh; struct stat st; if ( (unsigned)snprintf(fname, sizeof fname, "%s/.revsh/tgui-presets", getenv("HOME")) >= sizeof fname) return null; bnp = strrchr(fname, '/'); bnp[0] = '\0'; if (stat(fname, &st) < 0) { if (wrait) mkdir(fname, 0700); } else chmod(fname, 0700); bnp[0] = '/'; fh = fopen(fname, wrait? "w": "r"); if (fh == null) return null; return fh; } void load_listview() { char ident[512]; char * remote, *user, *s; FILE * fh = open_listview_file(false); #if M4EMO add_to_listview("Identification", "Remote Host", "Username"); #endif if (! fh) return; while (fgets(ident, sizeof ident, fh) != null) { remote = strchr(ident, '|'); if (remote == null) continue; *remote++ = '\0'; user = strchr(remote, '|'); if (user == null) continue; *user++ = '\0'; for (s = user; *s; s++) if (s[0] <= 0x20) { s[0] = '\0'; break; } add_to_listview(ident, remote, user); } fclose(fh); } void save_listview() { FILE * fh = open_listview_file(true); GtkTreeModel * model; GtkTreeIter iter; if (fh == null) return; model = gtk_tree_view_get_model(GTK_TREE_VIEW(G.lview)); if (gtk_tree_model_get_iter_first (model, &iter)) do { gchar * str; gtk_tree_model_get(model, &iter, 0, &str, -1); #if M4EMO if (strcmp(str, "Identification") == 0) { g_free(str); continue; } #endif fputs(str, fh); fputc('|', fh); g_free(str); gtk_tree_model_get(model, &iter, 1, &str, -1); fputs(str, fh); fputc('|', fh); g_free(str); gtk_tree_model_get(model, &iter, 2, &str, -1); fputs(str, fh); fputc('\n', fh); g_free(str); } while (gtk_tree_model_iter_next(model, &iter)); fclose(fh); } gboolean scroll_view_to_end(gpointer data UU) { GtkTextIter iter; gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER (G.buffer), &iter); gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(G.tview), &iter, 0.0, true, 0.0, 1.0); G.buffer_scroll_activated = false; return false; } void tune_buffer() { int lines = gtk_text_buffer_get_line_count(G.buffer); if (lines > 64) { GtkTextIter start, end; gtk_text_buffer_get_start_iter(G.buffer, &start); gtk_text_buffer_get_iter_at_line(G.buffer, &end, lines - 64); gtk_text_buffer_delete(G.buffer, &start, &end); } } void write_to_buffer(const char * buf, int len) { GtkTextIter iter; gtk_text_buffer_get_end_iter(G.buffer, &iter); gtk_text_buffer_insert(G.buffer, &iter, buf, len); if (! G.buffer_scroll_activated) { g_idle_add((GSourceFunc)scroll_view_to_end, null); G.buffer_scroll_activated = true; } G.buffer_last_char_written = buf[len - 1]; tune_buffer(); } void printf_to_buffer(const char * format, ...) { char sbuf[512]; va_list ap; unsigned int l; va_start(ap, format); l = g_vsnprintf(sbuf, sizeof sbuf, format, ap); if (l >= sizeof sbuf) l = sizeof sbuf - 1; va_end(ap); write_to_buffer(sbuf, l); } #if M4EMO static void tie_focus_in(void) { gtk_entry_set_visibility(GTK_ENTRY(G.tie), false); } static void tie_text_handler(GtkEditable * editable, const gchar * text, gint length, gint * position UU, gpointer data UU) { d0(("keypress: %d: '%s'", length, text)); #if 0 if (length == 0 || strncmp(text, " Tap ", 5) == 0) return; #endif if (G.revsh_pty >= 0 && length > 0) write(G.revsh_pty, text, length); g_signal_stop_emission_by_name (editable, "insert_text"); #if 0 write_to_buffer(text, length); #endif } void tie_activate(GtkWidget * w UU, void * data UU) { if (G.revsh_pty >= 0) write(G.revsh_pty, "\r", 1); gtk_widget_grab_focus(G.tview); } #else /* ! M4EMO */ void key_pressed(GtkWidget * w UU, GdkEventKey * e, void * data UU) { /* deprecated or not, but easy -- and gtkentry example in faq uses similar trick. */ d0(("keypress: %d: '%s'", e->length, e->string)); if (G.revsh_pty >= 0 && e->length > 0) write(G.revsh_pty, e->string, e->length); #if 0 write_to_buffer(e->string, e->length); #endif } #endif /* M4EMO */ void copy_entry_text(char * s, GtkWidget * w, size_t l) { strncpy(s, gtk_entry_get_text(GTK_ENTRY(w)), l); s[l-1] = '\0'; } enum { CT_BEGIN_S, CT_BEGIN_D, CT_CONNECTING, CT_DISCONNECTED }; void lview_selection_changed(GtkTreeSelection * sel UU, GtkListStore * liststore UU) { if (G.connect_state >= CT_CONNECTING) /* XXX */ return; gtk_button_set_label(GTK_BUTTON(G.b1), "Delete"); G.connect_state = CT_BEGIN_D; gtk_widget_set_sensitive(G.b1, true); } void lview_row_activated(GtkTreeView * treeview, GtkTreePath * path, GtkTreeViewColumn * col, gpointer userdata) { GtkTreeModel * model; GtkTreeIter iter; model = gtk_tree_view_get_model(treeview); if (gtk_tree_model_get_iter(model, &iter, path)) { gchar * str; gtk_tree_model_get(model, &iter, 0, &str, -1); #if M4EMO if (strcmp(str, "Identification") == 0) { gtk_entry_set_text(GTK_ENTRY(G.remote), ""); gtk_entry_set_text(GTK_ENTRY(G.user), ""); g_free(str); return; } #endif gtk_entry_set_text(GTK_ENTRY(G.ident), str); g_free(str); gtk_tree_model_get(model, &iter, 1, &str, -1); gtk_entry_set_text(GTK_ENTRY(G.remote), str); g_free(str); gtk_tree_model_get(model, &iter, 2, &str, -1); gtk_entry_set_text(GTK_ENTRY(G.user), str); g_free(str); gtk_widget_set_sensitive(G.b1, false); } } static void te_focus_in(void) { if (G.connect_state >= CT_CONNECTING) /* XXX */ return; gtk_button_set_label(GTK_BUTTON(G.b1), "Save"); G.connect_state = CT_BEGIN_S; gtk_widget_set_sensitive(G.b1, true); } void clear_connection(void) { g_object_ref(G_OBJECT(G.tview)); gtk_container_remove(GTK_CONTAINER(G.swindow), G.tview); gtk_container_add(GTK_CONTAINER(G.swindow), G.lview); /* XXX Should I unref G.lview here ??? (well, more refs doesn't hurt) */ gtk_button_set_label(GTK_BUTTON(G.b1), "Save"); gtk_button_set_label(GTK_BUTTON(G.b2), "Connect"); gtk_widget_set_sensitive(G.b1, false); gtk_widget_set_sensitive(G.b2, true); G.connect_state = CT_BEGIN_S; } void handle_dest_save() { add_to_listview(gtk_entry_get_text(GTK_ENTRY(G.ident)), gtk_entry_get_text(GTK_ENTRY(G.remote)), gtk_entry_get_text(GTK_ENTRY(G.user))); save_listview(); gtk_widget_set_sensitive(G.b1, false); } void handle_dest_delete() { GtkTreeSelection* sel; GtkTreeModel * model; GtkTreeIter selected_row; sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(G.lview)); if (gtk_tree_selection_get_selected(sel, &model, &selected_row)) { #if M4EMO char * str; gtk_tree_model_get(model, &selected_row, 0, &str, -1); if (strcmp(str, "Identification") == 0) { g_free(str); return; } g_free(str); #endif gtk_list_store_remove(GTK_LIST_STORE(model), &selected_row); } save_listview(); gtk_widget_set_sensitive(G.b1, false); } void button1_clicked(void) { switch (G.connect_state) { case CT_BEGIN_S: handle_dest_save(); break; case CT_BEGIN_D: handle_dest_delete(); break; case CT_DISCONNECTED: clear_connection(); break; } } void do_disconnected(void) { gtk_widget_set_sensitive(G.b1, true); gtk_widget_set_sensitive(G.b2, false); G.connect_state = CT_DISCONNECTED; } void do_disconnect(void) { if (G.revsh_pid > 0) { kill(G.revsh_pid, G.nextsig); G.nextsig = 9; } else do_disconnected(); } gboolean pty_input(GIOChannel * source, GIOCondition condition UU, gpointer data UU) { char buf[1024]; int len; len = read(G.revsh_pty, buf, sizeof buf); d0(("len %d %d:%s\n", len, errno, strerror(errno))); if (len <= 0) { /* FIXME, make sure process exits... */ close(G.revsh_pty); G.revsh_pty = -1; g_io_channel_unref(source); /* refcnt 1 -> 0 */ if (G.buffer_last_char_written != '\n') write_to_buffer("\n", 1); if (G.revsh_pid > 0) (void)kill(G.revsh_pid, SIGTERM); printf_to_buffer("*** RevSH exit ***\n"); /* XXX EOF */ #if M4EMO gtk_widget_hide(G.tie); #endif // is this right place -- or should sigchld_handler call ... do_disconnected(); return false; } write_to_buffer(buf, len); return true; } void sigchld_handler(int sig UU) { (void)wait(null); G.revsh_pid = 0; G.nextsig = 15; } /* This is for convenience, more "washing" (like clearing spaces) could be added but I'll let user choose... */ void lowcase_str(char * str) { int c; for (; (c = *str) != '\0'; str++) if (isupper(c)) *str = tolower(c); } void do_connect(void) { char itext[128]; char rtext[128]; char utext[128]; bool proceed; copy_entry_text(itext, G.ident, sizeof itext); lowcase_str(itext); copy_entry_text(rtext, G.remote, sizeof rtext); copy_entry_text(utext, G.user, sizeof utext); /* lowcase_str(utext); */ g_object_ref(G_OBJECT(G.lview)); gtk_container_remove(GTK_CONTAINER(G.swindow), G.lview); gtk_container_add(GTK_CONTAINER(G.swindow), G.tview); /* XXX Should I unref G.tview here ??? (well, more refs doesn't hurt) */ gtk_widget_grab_focus(G.tview); gtk_button_set_label(GTK_BUTTON(G.b1), "Reset"); gtk_widget_set_sensitive(G.b1, false); gtk_button_set_label(GTK_BUTTON(G.b2), "Disconnect"); proceed = true; if (strlen(itext) == 0) { printf_to_buffer("ERROR: Identification string not given\n"); proceed = false; } if (strlen(rtext) == 0) { printf_to_buffer("ERROR: Remote host missing\n"); proceed = false; } if (strlen(utext) == 0) { printf_to_buffer("ERROR: User name not given\n"); proceed = false; } if (! proceed) { do_disconnected(); return; } G.connect_state = CT_CONNECTING; G.revsh_pty = run_secure_shell(&G.revsh_pid, itext, utext, rtext); if (G.revsh_pty < 0) { printf_to_buffer("Failure creating revsh command..."); do_disconnect(); return; } G.iochannel = g_io_channel_unix_new(G.revsh_pty); g_io_add_watch(G.iochannel, G_IO_IN | G_IO_HUP, pty_input, null); /* I have to check later from doc/code ...*/ /* g_io_channel_unref(G.iochannel); *//* refcnt 2 -> 1 */ #if M4EMO gtk_entry_set_visibility(GTK_ENTRY(G.tie), true); gtk_widget_show(G.tie); #endif } void button2_clicked(void) { switch (G.connect_state) { case CT_BEGIN_S: case CT_BEGIN_D: do_connect(); break; case CT_CONNECTING: do_disconnect(); break; } } void activate_user_widget(GtkWidget * w UU, void * data UU) { gtk_widget_grab_focus(GTK_WIDGET(G.user)); } #if 0 static void dummy(void) { } #endif void main_window(int * rv) { char identstr[256]; char * p; strcpy(identstr, getusername(60)); p = identstr + strlen(identstr); *p++ = '@'; gethostname(p, 192); gtk_widget_show(G.tview = aTextView(G.buffer = aTextBuffer())); aWindow("RevSH Tunnel (" PRJ_VER ")", main_window_delete_event, rv, 4, false, true, aVBox(false, 3, aTable(4, false, aLabel("Identification:"), 1, /* \ */ G.ident = anEntry(identstr, 40), 3, aLabel("Remote Host:"), 1, /* \ */ G.remote = anEntry(null, 40), 3, aLabel("Username:"), 1, /* \ */ G.user = anEntry("", 20), 1, /* \ */ G.b1 = aButton("Save", button1_clicked, null), 1, /* \ */ G.b2 = aButton("Connect", button2_clicked, null), 1, null), false, false, 0, G.swindow = aScrolledWindow( G.lview = aListView(lview_selection_changed, 3, G_TYPE_STRING, "Ident", G_TYPE_STRING, "Remote", G_TYPE_STRING, "User")), true, true, 0, #if M4EMO #define TETXT " Tap this space to enter input on the terminal view above " /*gtk_entry_set_text(GTK_ENTRY(G.tie), TETXT); */ G.tie = anEntry(TETXT, 20), false, false, 0, #undef TETXT #endif null)); #if M4EMO gtk_widget_hide(G.tie); g_signal_connect(G_OBJECT(G.tie), "focus-in-event", G_CALLBACK(tie_focus_in), null); g_signal_connect(G_OBJECT(G.tie), "insert-text", G_CALLBACK(tie_text_handler), null); g_signal_connect(G_OBJECT(G.tie), "activate", G_CALLBACK(tie_activate), null); #else g_signal_connect(G_OBJECT(G.tview), "key-press-event", G_CALLBACK(key_pressed), null); gtk_widget_add_events(G.tview, GDK_KEY_PRESS_MASK); /* to make sure */ #endif g_signal_connect(G_OBJECT(G.remote), "activate", G_CALLBACK(activate_user_widget), null); gtk_entry_set_activates_default(GTK_ENTRY(G.user), true); GTK_WIDGET_SET_FLAGS (G.b2, GTK_CAN_DEFAULT); gtk_widget_grab_default(G.b2); gtk_widget_grab_focus(GTK_WIDGET(G.remote)); g_signal_connect(G_OBJECT(G.ident), "focus-in-event", G_CALLBACK(te_focus_in), null); g_signal_connect(G_OBJECT(G.remote), "focus-in-event", G_CALLBACK(te_focus_in), null); g_signal_connect(G_OBJECT(G.user), "focus-in-event", G_CALLBACK(te_focus_in), null); g_signal_connect(G.lview, "row-activated", G_CALLBACK(lview_row_activated), null); load_listview(); } void program_init(void) { #if 0 && M4EMO > 1 // not needed anymore char * path = getenv("PATH"); char * b; int l; #endif struct sigaction action; action.sa_handler = sigchld_handler; action.sa_flags = SA_RESTART|SA_NOCLDSTOP;/* NOCLDSTOP needed if ptraced */ sigemptyset(&action.sa_mask); sigaction(SIGCHLD, &action, NULL); #if 0 && M4EMO > 1 // not needed anymore if (path) l = strlen(path); else l = 0; b = malloc(5 + l + 1 + 25); if (!b) exit(1); memcpy(b, "PATH=", 5); memcpy(b + 5, path, l); b[5 + l] = ':'; memcpy(b + 5 + l + 1, "/var/lib/install/usr/bin", 25); d0(("path: %s", b)); putenv(b); #endif } int main(int argc, char ** argv) { int rv = 1; #if M4EMO > 1 #define DBUS_ESCAPE_HAX 1 #if ! DBUS_ESCAPE_HAX osso_context_t * osso_context; #endif #endif /* syslog(5, "running revsh: argc: %d\n", argc); */ G_init(); #if M4EMO > 1 #if DBUS_ESCAPE_HAX /* FIXME cheating D-BUS for now. Maybe fixed in (near) future */ /* do *before* gtk_init() */ if (fork()) { sleep(1); _exit(0); } close(0); open("/dev/null", O_RDWR); dup2(0, 1); dup2(0, 2); setsid(); #endif #endif gtk_init(&argc, &argv); #if M4EMO > 1 #if ! DBUS_ESCAPE_HAX /* do *after* gtk_init() */ osso_context = osso_initialize("revsh", PRJ_VER, true, null); #endif #endif program_init(); main_window(&rv); gtk_main(); #if M4EMO > 1 #if ! DBUS_ESCAPE_HAX osso_deinitialize(osso_context); #endif #endif return rv; } /* * Local variables: * mode: c * c-file-style: "stroustrup" * tab-width: 8 * compile-command: "sh revsh-tunnel-gui.c" * End: */