fix order of OEMparameters to enable BIOS SOL on newer AMT generations
[amt] / gamt.c
1 /*
2 * amtterm -- Intel AMT serial-over-lan client, gtk version.
3 *
4 * Copyright (C) 2007 Gerd Hoffmann <kraxel@redhat.com
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <locale.h>
28 #include <signal.h>
29 #include <ctype.h>
30
31 #include <gdk/gdk.h>
32 #include <gdk/gdkx.h>
33 #include <gtk/gtk.h>
34 #include <vte/vte.h>
35
36 #include "parseconfig.h"
37 #include "redir.h"
38
39 #define APPNAME "gamt"
40
41 struct gamt_window {
42 /* gtk stuff */
43 GtkActionGroup *ag;
44 GtkUIManager *ui;
45 GtkWidget *win;
46 GtkWidget *vte;
47 GtkWidget *status;
48 GtkWidget *icon;
49
50 GtkActionGroup *hosts_ag;
51 guint hosts_id;
52
53 /* sol stuff */
54 struct redir redir;
55 GIOChannel *ch;
56 guint id;
57 };
58
59 static const char *state_stock[] = {
60 [ REDIR_NONE ] = GTK_STOCK_DISCONNECT,
61 #if 0
62 [ REDIR_CONNECT ] = GTK_STOCK_,
63 [ REDIR_INIT ] = GTK_STOCK_,
64 [ REDIR_AUTH ] = GTK_STOCK_,
65 [ REDIR_INIT_SOL ] = GTK_STOCK_,
66 #endif
67 [ REDIR_RUN_SOL ] = GTK_STOCK_CONNECT,
68 #if 0
69 [ REDIR_INIT_IDER ] = GTK_STOCK_,
70 [ REDIR_RUN_IDER ] = GTK_STOCK_,
71 [ REDIR_CLOSING ] = GTK_STOCK_,
72 #endif
73 [ REDIR_CLOSED ] = GTK_STOCK_DISCONNECT,
74 [ REDIR_ERROR ] = GTK_STOCK_DISCONNECT,
75 };
76
77 static char amt_host[64];
78 static char amt_port[16];
79 static char amt_user[32] = "admin";
80 static char amt_pass[32];
81 static int amt_trace;
82 static int amt_debug;
83
84 static int gamt_getstring(GtkWidget *window, char *title, char *message,
85 char *dest, int dlen, int hide);
86 static int gamt_connect(struct gamt_window *gamt);
87 static void gamt_rebuild_hosts(struct gamt_window *gamt);
88
89 /* ------------------------------------------------------------------ */
90
91 #define CFG_SECTION "config", "config"
92 #define CFG_FONT CFG_SECTION, "font"
93 #define CFG_FOREGROUND CFG_SECTION, "foreground"
94 #define CFG_BACKGROUND CFG_SECTION, "background"
95 #define CFG_BLINK CFG_SECTION, "blink-cursor"
96
97 /* ------------------------------------------------------------------ */
98
99 static void menu_cb_connect(GtkAction *action, void *data)
100 {
101 struct gamt_window *gamt = data;
102 int rc;
103
104 if (gamt->redir.state != REDIR_NONE &&
105 gamt->redir.state != REDIR_CLOSED &&
106 gamt->redir.state != REDIR_ERROR)
107 /* already have an active connection */
108 return;
109
110 rc = gamt_getstring(gamt->win, "Connecting",
111 "Connect to host ?",
112 amt_host, sizeof(amt_host), 0);
113 if (0 != rc)
114 return;
115
116 gamt_connect(gamt);
117 }
118
119 static void menu_cb_connect_to(GtkAction *action, void *data)
120 {
121 struct gamt_window *gamt = data;
122
123 if (gamt->redir.state != REDIR_NONE &&
124 gamt->redir.state != REDIR_CLOSED &&
125 gamt->redir.state != REDIR_ERROR)
126 /* already have an active connection */
127 return;
128
129 if (1 != sscanf(gtk_action_get_name(action), "ConnectTo_%s", amt_host))
130 return;
131 gamt_connect(gamt);
132 }
133
134 static void menu_cb_disconnect(GtkAction *action, void *data)
135 {
136 struct gamt_window *gamt = data;
137
138 if (gamt->redir.state != REDIR_RUN_SOL)
139 return;
140 redir_sol_stop(&gamt->redir);
141 }
142
143 static void menu_cb_config_font(GtkAction *action, void *data)
144 {
145 struct gamt_window *gamt = data;
146 GtkWidget *dialog;
147 char *fontname;
148
149 dialog = gtk_font_selection_dialog_new("Terminal font");
150 fontname = cfg_get_str(CFG_FONT);
151 gtk_font_selection_dialog_set_font_name
152 (GTK_FONT_SELECTION_DIALOG(dialog), fontname);
153
154 gtk_widget_show_all(dialog);
155 switch (gtk_dialog_run(GTK_DIALOG(dialog))) {
156 case GTK_RESPONSE_OK:
157 fontname = gtk_font_selection_dialog_get_font_name
158 (GTK_FONT_SELECTION_DIALOG(dialog));
159 vte_terminal_set_font_from_string(VTE_TERMINAL(gamt->vte), fontname);
160 cfg_set_str(CFG_FONT, fontname);
161 break;
162 }
163 gtk_widget_destroy(dialog);
164 }
165
166 static int pickcolor(char *title, GdkColor *color)
167 {
168 GtkWidget *dialog;
169 GtkColorSelection *csel;
170 int rc = -1;
171
172 dialog = gtk_color_selection_dialog_new(title);
173 csel = GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(dialog)->colorsel);
174 gtk_color_selection_set_has_opacity_control(csel, FALSE);
175 gtk_color_selection_set_current_color(csel, color);
176
177 gtk_widget_show_all(dialog);
178 switch (gtk_dialog_run(GTK_DIALOG(dialog))) {
179 case GTK_RESPONSE_OK:
180 gtk_color_selection_get_current_color(csel, color);
181 rc = 0;
182 }
183 gtk_widget_destroy(dialog);
184 return rc;
185 }
186
187 static void menu_cb_config_fg(GtkAction *action, void *data)
188 {
189 struct gamt_window *gamt = data;
190 GdkColor color = {0,0,0,0};
191 char name[16];
192
193 gdk_color_parse(cfg_get_str(CFG_FOREGROUND), &color);
194 if (0 != pickcolor("Text color", &color))
195 return;
196 vte_terminal_set_color_foreground(VTE_TERMINAL(gamt->vte), &color);
197 snprintf(name, sizeof(name), "#%04x%04x%04x",
198 color.red, color.green, color.blue);
199 cfg_set_str(CFG_FOREGROUND, name);
200 }
201
202 static void menu_cb_config_bg(GtkAction *action, void *data)
203 {
204 struct gamt_window *gamt = data;
205 GdkColor color = {0,0,0,0};
206 char name[16];
207
208 gdk_color_parse(cfg_get_str(CFG_BACKGROUND), &color);
209 if (0 != pickcolor("Background color", &color))
210 return;
211 vte_terminal_set_color_background(VTE_TERMINAL(gamt->vte), &color);
212 snprintf(name, sizeof(name), "#%04x%04x%04x",
213 color.red, color.green, color.blue);
214 cfg_set_str(CFG_BACKGROUND, name);
215 }
216
217 static void menu_cb_blink_cursor(GtkToggleAction *action, gpointer user_data)
218 {
219 struct gamt_window *gamt = user_data;
220 gboolean state = gtk_toggle_action_get_active(action);
221
222 if (amt_debug)
223 fprintf(stderr, "%s: %s\n", __FUNCTION__, state ? "on" : "off");
224 cfg_set_bool(CFG_BLINK, state);
225 vte_terminal_set_cursor_blinks(VTE_TERMINAL(gamt->vte), state);
226 }
227
228 static void menu_cb_quit(GtkAction *action, void *data)
229 {
230 struct gamt_window *gamt = data;
231
232 gtk_widget_destroy(gamt->win);
233 }
234
235 static void show_manpage(char *page, char *section)
236 {
237 char buf[64];
238
239
240 switch(fork()) {
241 case -1:
242 perror("fork");
243 break;
244 case 0:
245 /* child: try xdg-open first ... */
246 snprintf(buf, sizeof(buf), "man:%s(%s)", page, section);
247 execlp("xdg-open", "xdg-open", buf, NULL);
248 perror("execlp(xdg-open)");
249 /* ... fallback is an xterm with man */
250 snprintf(buf, sizeof(buf), "manual page: %s(%s)", page, section);
251 execlp("xterm", "xterm",
252 "-title", buf,
253 "-e", "man", section, page,
254 NULL);
255 perror("execlp(xterm)");
256 exit(1);
257 break;
258 default:
259 /* parent */
260 break;
261 }
262 }
263
264 static void menu_cb_man_gamt(GtkAction *action, void *data)
265 {
266 show_manpage("gamt", "1");
267 }
268
269 static void menu_cb_man_amt_howto(GtkAction *action, void *data)
270 {
271 show_manpage("amt-howto", "7");
272 }
273
274 static void menu_cb_about(GtkAction *action, void *data)
275 {
276 static char *comments = "Intel AMT serial-over-lan client";
277 static char *copyright = "(c) 2007 Gerd Hoffmann";
278 static char *website = "http://dl.bytesex.org/releases/amtterm/";
279 static char *authors[] = { "Gerd Hoffmann <kraxel@redhat.com>", NULL };
280 struct gamt_window *gamt = data;
281
282 gtk_show_about_dialog(GTK_WINDOW(gamt->win),
283 "authors", authors,
284 "comments", comments,
285 "copyright", copyright,
286 "logo-icon-name", GTK_STOCK_ABOUT,
287 "version", VERSION,
288 "website", website,
289 // "license", "GPLv2+",
290 NULL);
291 }
292
293 static void destroy_cb(GtkWidget *widget, gpointer data)
294 {
295 struct gamt_window *gamt = data;
296
297 gtk_main_quit();
298 free(gamt);
299 }
300
301 /* ------------------------------------------------------------------ */
302
303 static int recv_gtk(void *cb_data, unsigned char *buf, int len)
304 {
305 struct gamt_window *gamt = cb_data;
306 vte_terminal_feed(VTE_TERMINAL(gamt->vte), buf, len);
307 return 0;
308 }
309
310 static void state_gtk(void *cb_data, enum redir_state old, enum redir_state new)
311 {
312 struct gamt_window *gamt = cb_data;
313 unsigned char buf[128];
314 int last;
315
316 switch (new) {
317 case REDIR_ERROR:
318 #if 0
319 snprintf(buf, sizeof(buf), "%s: %s FAILED (%s)", gamt->redir.host,
320 redir_state_desc(old), gamt->redir.err);
321 #else
322 snprintf(buf, sizeof(buf), "%s: ERROR: %s", gamt->redir.host,
323 gamt->redir.err);
324 #endif
325 if (old == REDIR_AUTH) {
326 /* ask for a new password next time ... */
327 strcpy(amt_pass, "");
328 }
329 break;
330 case REDIR_RUN_SOL:
331 last = cfg_get_int("config", "hosts", gamt->redir.host, 0);
332 cfg_set_int("config", "hosts", gamt->redir.host, time(NULL));
333 if (!last)
334 gamt_rebuild_hosts(gamt);
335 /* fall through */
336 default:
337 snprintf(buf, sizeof(buf), "%s: %s", gamt->redir.host,
338 redir_state_desc(new));
339 break;
340 }
341 if (state_stock[new])
342 gtk_image_set_from_stock(GTK_IMAGE(gamt->icon), state_stock[new],
343 GTK_ICON_SIZE_SMALL_TOOLBAR);
344 gtk_label_set_text(GTK_LABEL(gamt->status), buf);
345 }
346
347 static void user_input(VteTerminal *vte, gchar *buf, guint len,
348 gpointer data)
349 {
350 struct gamt_window *gamt = data;
351
352 if (gamt->redir.state == REDIR_RUN_SOL)
353 redir_sol_send(&gamt->redir, buf, len);
354 }
355
356 /* ------------------------------------------------------------------ */
357
358 static const GtkActionEntry entries[] = {
359 {
360 .name = "FileMenu",
361 .label = "_File",
362 },{
363 .name = "ConfigMenu",
364 .label = "_Options",
365 },{
366 .name = "HostMenu",
367 .label = "Ho_sts",
368 },{
369 .name = "HelpMenu",
370 .label = "_Help",
371 },{
372
373 /* File menu */
374 .name = "Connect",
375 .stock_id = GTK_STOCK_CONNECT,
376 .label = "_Connect ...",
377 .callback = G_CALLBACK(menu_cb_connect),
378 },{
379 .name = "Disconnect",
380 .stock_id = GTK_STOCK_DISCONNECT,
381 .label = "_Disconnect",
382 .callback = G_CALLBACK(menu_cb_disconnect),
383 },{
384 .name = "Quit",
385 .stock_id = GTK_STOCK_QUIT,
386 .label = "_Quit",
387 .callback = G_CALLBACK(menu_cb_quit),
388 },{
389
390 /* Config menu */
391 .name = "VteFont",
392 .stock_id = GTK_STOCK_SELECT_FONT,
393 .label = "Terminal _font ...",
394 .callback = G_CALLBACK(menu_cb_config_font),
395 },{
396 .name = "VteForeground",
397 // .stock_id = GTK_STOCK_SELECT_COLOR,
398 .label = "_Text Color ...",
399 .callback = G_CALLBACK(menu_cb_config_fg),
400 },{
401 .name = "VteBackground",
402 .label = "_Background Color ...",
403 .callback = G_CALLBACK(menu_cb_config_bg),
404 },{
405
406 /* Help menu */
407 .name = "ManGamt1",
408 .stock_id = GTK_STOCK_HELP,
409 .label = "Manual Page",
410 .callback = G_CALLBACK(menu_cb_man_gamt),
411 },{
412 .name = "ManAmtHowto7",
413 .stock_id = GTK_STOCK_INFO,
414 .label = "AMT HowTo",
415 .callback = G_CALLBACK(menu_cb_man_amt_howto),
416 },{
417 .name = "About",
418 .stock_id = GTK_STOCK_ABOUT,
419 .label = "_About ...",
420 .callback = G_CALLBACK(menu_cb_about),
421 }
422 };
423
424 static const GtkToggleActionEntry tentries[] = {
425 {
426 .name = "BlinkCursor",
427 .label = "Blinking cursor",
428 .callback = G_CALLBACK(menu_cb_blink_cursor),
429 }
430 };
431
432 static char ui_xml[] =
433 "<ui>\n"
434 " <menubar action='MainMenu'>\n"
435 " <menu action='FileMenu'>\n"
436 " <menuitem action='Connect'/>\n"
437 " <menuitem action='Disconnect'/>\n"
438 " <separator/>\n"
439 " <menuitem action='Quit'/>\n"
440 " </menu>\n"
441 " <menu action='HostMenu'>\n"
442 " </menu>\n"
443 " <menu action='ConfigMenu'>\n"
444 " <menuitem action='VteFont'/>\n"
445 " <menuitem action='VteForeground'/>\n"
446 " <menuitem action='VteBackground'/>\n"
447 " <separator/>\n"
448 " <menuitem action='BlinkCursor'/>\n"
449 " </menu>\n"
450 " <menu action='HelpMenu'>\n"
451 " <menuitem action='ManGamt1'/>\n"
452 " <menuitem action='ManAmtHowto7'/>\n"
453 " <separator/>\n"
454 " <menuitem action='About'/>\n"
455 " </menu>\n"
456 " </menubar>\n"
457 " <toolbar action='ToolBar'>\n"
458 " <toolitem action='Quit'/>\n"
459 " <toolitem action='Connect'/>\n"
460 " <toolitem action='Disconnect'/>\n"
461 " </toolbar>\n"
462 "</ui>\n";
463
464 static char hosts_xml_start[] =
465 "<ui>\n"
466 " <menubar name='MainMenu'>\n"
467 " <menu action='HostMenu'>\n";
468
469 static char hosts_xml_end[] =
470 " </menu>\n"
471 " </menubar>\n"
472 "</ui>\n";
473
474 /* ------------------------------------------------------------------ */
475
476 static int gamt_getstring(GtkWidget *window, char *title, char *message,
477 char *dest, int dlen, int hide)
478 {
479 GtkWidget *dialog, *label, *entry;
480 const char *txt;
481 int retval;
482
483 /* Create the widgets */
484 dialog = gtk_dialog_new_with_buttons(title,
485 GTK_WINDOW(window),
486 GTK_DIALOG_DESTROY_WITH_PARENT,
487 GTK_STOCK_OK,
488 GTK_RESPONSE_ACCEPT,
489 GTK_STOCK_CANCEL,
490 GTK_RESPONSE_REJECT,
491 NULL);
492 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
493
494 label = gtk_label_new(message);
495 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
496
497 entry = gtk_entry_new();
498 gtk_entry_set_text(GTK_ENTRY(entry), dest);
499 gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
500 if (hide)
501 gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
502
503 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
504 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), entry);
505 gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), 10);
506 #if 0 /* FIXME: doesn't work ... */
507 gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), 10);
508 #endif
509
510 /* show and wait for response */
511 gtk_widget_show_all(dialog);
512 switch (gtk_dialog_run(GTK_DIALOG(dialog))) {
513 case GTK_RESPONSE_ACCEPT:
514 txt = gtk_entry_get_text(GTK_ENTRY(entry));
515 snprintf(dest, dlen, "%s", txt);
516 retval = 0;
517 break;
518 default:
519 retval = -1;
520 break;
521 }
522 gtk_widget_destroy(dialog);
523 return retval;
524 }
525
526 static gboolean gamt_data(GIOChannel *source, GIOCondition condition,
527 gpointer data)
528 {
529 struct gamt_window *gamt = data;
530
531 redir_data(&gamt->redir);
532
533 if (gamt->redir.state == REDIR_CLOSED ||
534 gamt->redir.state == REDIR_ERROR) {
535 g_source_destroy(g_main_context_find_source_by_id
536 (g_main_context_default(), gamt->id));
537 gamt->id = 0;
538 gamt->ch = NULL;
539 }
540 return TRUE;
541 }
542
543 static void gamt_rebuild_hosts(struct gamt_window *gamt)
544 {
545 int count, size, pos;
546 char *hosts_xml, *host, action[128];
547 GtkActionEntry entry;
548 GError *err = NULL;
549
550 /* remove */
551 if (gamt->hosts_id) {
552 gtk_ui_manager_remove_ui(gamt->ui, gamt->hosts_id);
553 gamt->hosts_id = 0;
554 }
555 if (gamt->hosts_ag) {
556 gtk_ui_manager_remove_action_group(gamt->ui, gamt->hosts_ag);
557 g_object_unref(gamt->hosts_ag);
558 gamt->hosts_ag = NULL;
559 }
560
561 /* build */
562 memset(&entry, 0, sizeof(entry));
563 entry.callback = G_CALLBACK(menu_cb_connect_to);
564 gamt->hosts_ag = gtk_action_group_new("HostActions");
565 count = cfg_entries_count("config", "hosts");
566 size = 128 * count + sizeof(hosts_xml_start) + sizeof(hosts_xml_end);
567 hosts_xml = malloc(size); pos = 0;
568 pos += sprintf(hosts_xml+pos, "%s", hosts_xml_start);
569 for (host = cfg_entries_first("config", "hosts");
570 NULL != host;
571 host = cfg_entries_next("config", "hosts", host)) {
572 snprintf(action, sizeof(action), "ConnectTo_%s", host);
573 pos += snprintf(hosts_xml+pos, 128,
574 " <menuitem action='%s'/>\n",
575 action);
576 entry.name = action;
577 entry.label = host;
578 gtk_action_group_add_actions(gamt->hosts_ag, &entry, 1, gamt);
579 }
580 pos += sprintf(hosts_xml+pos, "%s", hosts_xml_end);
581
582 /* add */
583 gtk_ui_manager_insert_action_group(gamt->ui, gamt->hosts_ag, 1);
584 gamt->hosts_id = gtk_ui_manager_add_ui_from_string(gamt->ui, hosts_xml, -1, &err);
585 if (!gamt->hosts_id) {
586 g_message("building host menu failed: %s", err->message);
587 g_error_free(err);
588 }
589 }
590
591 static int gamt_connect(struct gamt_window *gamt)
592 {
593 int rc;
594
595 if (0 == strlen(amt_pass)) {
596 char msg[128];
597
598 snprintf(msg, sizeof(msg), "AMT password for %s@%s ?",
599 amt_user, amt_host);
600 rc = gamt_getstring(gamt->win, "Authentication", msg,
601 amt_pass, sizeof(amt_pass), 1);
602 if (0 != rc)
603 return -1;
604 }
605
606 memset(&gamt->redir, 0, sizeof(gamt->redir));
607 memcpy(&gamt->redir.type, "SOL ", 4);
608
609 snprintf(gamt->redir.host, sizeof(gamt->redir.host), "%s", amt_host);
610 snprintf(gamt->redir.port, sizeof(gamt->redir.port), "%s", amt_port);
611 snprintf(gamt->redir.user, sizeof(gamt->redir.user), "%s", amt_user);
612 snprintf(gamt->redir.pass, sizeof(gamt->redir.pass), "%s", amt_pass);
613
614 gamt->redir.verbose = 1;
615 gamt->redir.trace = amt_trace;
616 gamt->redir.cb_data = gamt;
617 gamt->redir.cb_recv = recv_gtk;
618 gamt->redir.cb_state = state_gtk;
619
620 if (-1 == redir_connect(&gamt->redir))
621 return -1;
622
623 fcntl(gamt->redir.sock, F_SETFD, FD_CLOEXEC);
624 vte_terminal_reset(VTE_TERMINAL(gamt->vte), TRUE, TRUE);
625 gamt->ch = g_io_channel_unix_new(gamt->redir.sock);
626 gamt->id = g_io_add_watch(gamt->ch, G_IO_IN, gamt_data, gamt);
627 redir_start(&gamt->redir);
628 return 0;
629 }
630
631 static struct gamt_window *gamt_window()
632 {
633 GtkWidget *vbox, *hbox, *frame, *item;
634 GdkColor color;
635 GError *err;
636 gboolean state;
637 struct gamt_window *gamt;
638 char *str;
639
640 gamt = malloc(sizeof(*gamt));
641 if (NULL == gamt)
642 return NULL;
643 memset(gamt,0,sizeof(*gamt));
644
645 /* gtk toplevel */
646 gamt->win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
647 g_signal_connect(G_OBJECT(gamt->win), "destroy",
648 G_CALLBACK(destroy_cb), gamt);
649
650 /* menu + toolbar */
651 gamt->ui = gtk_ui_manager_new();
652 gamt->ag = gtk_action_group_new("MenuActions");
653 gtk_action_group_add_actions(gamt->ag, entries, G_N_ELEMENTS(entries), gamt);
654 gtk_action_group_add_toggle_actions(gamt->ag, tentries,
655 G_N_ELEMENTS(tentries), gamt);
656 gtk_ui_manager_insert_action_group(gamt->ui, gamt->ag, 0);
657 #if 0
658 GtkAccelGroup *accel = gtk_ui_manager_get_accel_group(gamt->ui);
659 gtk_window_add_accel_group(GTK_WINDOW(gamt->win), accel);
660 #endif
661
662 err = NULL;
663 if (!gtk_ui_manager_add_ui_from_string(gamt->ui, ui_xml, -1, &err)) {
664 g_message("building menus failed: %s", err->message);
665 g_error_free(err);
666 exit(1);
667 }
668 gamt_rebuild_hosts(gamt);
669
670 /* vte terminal */
671 gamt->vte = vte_terminal_new();
672 g_signal_connect(gamt->vte, "commit", G_CALLBACK(user_input), gamt);
673 vte_terminal_set_scrollback_lines(VTE_TERMINAL(gamt->vte), 4096);
674 str = cfg_get_str(CFG_FONT);
675 vte_terminal_set_font_from_string(VTE_TERMINAL(gamt->vte), str);
676
677 /* FIXME: make configurable */
678 vte_terminal_set_backspace_binding(VTE_TERMINAL(gamt->vte),
679 VTE_ERASE_ASCII_BACKSPACE);
680 vte_terminal_set_delete_binding(VTE_TERMINAL(gamt->vte),
681 VTE_ERASE_AUTO);
682
683 item = gtk_ui_manager_get_widget(gamt->ui, "/MainMenu/ConfigMenu/BlinkCursor");
684 state = cfg_get_bool(CFG_BLINK, 0);
685 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), state);
686 vte_terminal_set_cursor_blinks(VTE_TERMINAL(gamt->vte), state);
687
688 /* other widgets */
689 gamt->status = gtk_label_new("idle");
690 gtk_misc_set_alignment(GTK_MISC(gamt->status), 0, 0.5);
691 gtk_misc_set_padding(GTK_MISC(gamt->status), 3, 1);
692 gamt->icon = gtk_image_new_from_stock(GTK_STOCK_DISCONNECT,
693 GTK_ICON_SIZE_SMALL_TOOLBAR);
694
695 /* Make a vbox and put stuff in */
696 vbox = gtk_vbox_new(FALSE, 1);
697 hbox = gtk_hbox_new(FALSE, 1);
698 gtk_container_set_border_width(GTK_CONTAINER(vbox), 1);
699 gtk_container_add(GTK_CONTAINER(gamt->win), vbox);
700 item = gtk_ui_manager_get_widget(gamt->ui, "/MainMenu");
701 gtk_box_pack_start(GTK_BOX(vbox), item, FALSE, FALSE, 0);
702 #if 0
703 item = gtk_ui_manager_get_widget(gamt->ui, "/ToolBar");
704 gtk_box_pack_start(GTK_BOX(vbox), item, FALSE, FALSE, 0);
705 #endif
706 gtk_box_pack_start(GTK_BOX(vbox), gamt->vte, TRUE, TRUE, 0);
707 gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
708
709 frame = gtk_frame_new(NULL);
710 gtk_container_add(GTK_CONTAINER(frame), gamt->status);
711 gtk_box_pack_start(GTK_BOX(hbox), frame, TRUE, TRUE, 0);
712
713 frame = gtk_frame_new(NULL);
714 gtk_container_add(GTK_CONTAINER(frame), gamt->icon);
715 gtk_box_pack_end(GTK_BOX(hbox), frame, FALSE, TRUE, 0);
716
717 /* display window */
718 gtk_widget_show_all(gamt->win);
719
720 str = cfg_get_str(CFG_FOREGROUND);
721 if (str) {
722 gdk_color_parse(str, &color);
723 vte_terminal_set_color_foreground(VTE_TERMINAL(gamt->vte), &color);
724 }
725 str = cfg_get_str(CFG_BACKGROUND);
726 if (str) {
727 gdk_color_parse(str, &color);
728 vte_terminal_set_color_background(VTE_TERMINAL(gamt->vte), &color);
729 }
730
731 return gamt;
732 }
733
734 /* ------------------------------------------------------------------ */
735
736 static void usage(FILE *fp)
737 {
738 fprintf(fp,
739 "\n"
740 "This is " APPNAME ", release " VERSION ", I'll establish\n"
741 "serial-over-lan (sol) connections to your Intel AMT boxes.\n"
742 "\n"
743 "usage: " APPNAME " [options] host\n"
744 "options:\n"
745 " -h print this text\n"
746 " -u user username (default: admin)\n"
747 " -p pass password (default: $AMT_PASSWORD)\n"
748 " -f font terminal font\n"
749 " -c color text color\n"
750 " -b color backgrounf color\n"
751 "\n"
752 "By default port 16994 is used.\n"
753 "If no password is given " APPNAME " will ask for one.\n"
754 "\n"
755 "-- \n"
756 "(c) 2007 Gerd Hoffmann <kraxel@redhat.com>\n"
757 "\n");
758 }
759
760 int
761 main(int argc, char *argv[])
762 {
763 Display *dpy;
764 struct gamt_window *gamt;
765 char configfile[256];
766 char *h;
767 int c;
768
769 if (NULL != (h = getenv("AMT_PASSWORD")))
770 snprintf(amt_pass, sizeof(amt_pass), "%s", h);
771
772 /* read config, make sure we have sane defaults */
773 snprintf(configfile, sizeof(configfile), "%s/.gamtrc", getenv("HOME"));
774 cfg_parse_file("config", configfile);
775 if (!cfg_get_str(CFG_FONT))
776 cfg_set_str(CFG_FONT, "monospace 12");
777 if (!cfg_get_str(CFG_FOREGROUND))
778 cfg_set_str(CFG_FOREGROUND, "gray");
779 if (!cfg_get_str(CFG_BACKGROUND))
780 cfg_set_str(CFG_BACKGROUND, "black");
781
782 gtk_init(&argc, &argv);
783 dpy = gdk_x11_display_get_xdisplay(gdk_display_get_default());
784 fcntl(ConnectionNumber(dpy),F_SETFD,FD_CLOEXEC);
785
786 for (;;) {
787 if (-1 == (c = getopt(argc, argv, "hdtu:p:f:c:b:")))
788 break;
789 switch (c) {
790 case 'd':
791 amt_debug++;
792 break;
793 case 't':
794 amt_trace++;
795 break;
796 case 'u':
797 snprintf(amt_user, sizeof(amt_user), "%s", optarg);
798 break;
799 case 'p':
800 snprintf(amt_pass, sizeof(amt_pass), "%s", optarg);
801 memset(optarg,'*',strlen(optarg)); /* rm passwd from ps list */
802 break;
803 case 'f':
804 cfg_set_str(CFG_FONT, optarg);
805 break;
806 case 'c':
807 cfg_set_str(CFG_FOREGROUND, optarg);
808 break;
809 case 'b':
810 cfg_set_str(CFG_BACKGROUND, optarg);
811 break;
812
813 case 'h':
814 usage(stdout);
815 exit(0);
816 default:
817 usage(stderr);
818 exit(1);
819 }
820 }
821
822 gamt = gamt_window();
823 if (NULL == gamt)
824 exit(1);
825
826 if (optind+1 <= argc) {
827 snprintf(amt_host, sizeof(amt_host), "%s", argv[optind]);
828 gamt_connect(gamt);
829 }
830
831 gtk_main();
832 cfg_write_file("config", configfile);
833 exit(0);
834 }
Impressum, Datenschutz