/* * Prepare the widget for being placed in the form. This implements * automatically positioning the widget and automatically resizing * the form if the widget is too large to fit. */ static void curses_form_widget_prepare(struct curses_form *cf, struct curses_widget *w) { /* * Link the widget to the form. */ w->form = cf; /* * Auto-position the widget to the center of the form, * if requested. */ if (w->flags & CURSES_WIDGET_CENTER) w->x = (cf->width - w->width) / 2; /* * If the widget's right edge exceeds the width of * the form, expand the form. */ dfui_debug("w->x=%d w->width=%d cf->width=%d : ", w->x, w->width, cf->width); if ((w->x + w->width + 1) > cf->width) cf->width = w->x + w->width + 1; dfui_debug("new cf->width=%d\n", cf->width); }
/* * Ask for, and subsequently receieve, a message from the backend. * msgtype should be one of the DFUI_FE_MSG_* constants. * This call is synchronous. * After this call, the null-terminated, encoded message is * available in T_NPIPE(c)->buf. */ dfui_err_t dfui_npipe_fe_ll_request(struct dfui_connection *c, char msgtype, const char *msg) { char *fmsg, *buf; int length; /* * First, assert that the connection is open. */ if (c == NULL || T_NPIPE(c)->in == NULL || T_NPIPE(c)->out == NULL) return(DFUI_FAILURE); /* * Construct a message. */ fmsg = malloc(strlen(msg) + 1); fmsg[0] = msgtype; strcpy(fmsg + 1, msg); dfui_debug("SEND<<%s>>\n", fmsg); /* * Send a NUL-terminated message to the backend. */ length = strlen(fmsg); fwrite(&length, 4, 1, T_NPIPE(c)->out); fwrite(fmsg, length, 1, T_NPIPE(c)->out); /* * Receive a reply from the backend. * If our message was a READY, this should be a message like PRESENT. * Otherwise it should simply be a READY. */ dfui_debug("WAITING<<>>\n"); fread(&length, 4, 1, T_NPIPE(c)->in); buf = malloc(length + 1); fread(buf, length, 1, T_NPIPE(c)->in); aura_buffer_set(c->ebuf, buf, length); free(buf); dfui_debug("RECV<<%s>>\n", aura_buffer_buf(c->ebuf)); free(fmsg); return(DFUI_SUCCESS); }
/* * Connect to the frontend. */ dfui_err_t dfui_tcp_be_start(struct dfui_connection *c) { struct sockaddr_in servaddr; int server_port; int tru = 1; server_port = atoi(c->rendezvous); /* * Create the tcp socket */ errno = 0; if ((T_TCP(c)->listen_sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) return(DFUI_FAILURE); dfui_debug("LISTEN_SOCKET<<%d>>\n", T_TCP(c)->listen_sd); if (setsockopt(T_TCP(c)->listen_sd, SOL_SOCKET, SO_REUSEADDR, &tru, sizeof(tru)) == -1) { return(DFUI_FAILURE); } bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(server_port); switch(inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr)) { case 0: warnx("inet_pton(): address not parseable"); return(DFUI_FAILURE); case 1: break; default: warn("inet_pton()"); return(DFUI_FAILURE); } if (bind(T_TCP(c)->listen_sd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) { warn("bind()"); return(DFUI_FAILURE); } dfui_debug("BOUND_ON<<%d>>\n", T_TCP(c)->listen_sd); if (listen(T_TCP(c)->listen_sd, 0) == -1) return(DFUI_FAILURE); dfui_debug("LISTENING_ON<<%d>>\n", T_TCP(c)->listen_sd); /* at this point we should be listening on the rendezvous port */ return(DFUI_SUCCESS); }
/* * Create a row of buttons, one for each action, at * the bottom of a curses_form. */ static void create_buttons(const struct dfui_form *f, struct curses_form *cf, int is_menu) { struct curses_widget *w; char name[80]; struct dfui_action *a; struct curses_widget *row_start = NULL; int left_acc = 1; const char *accel; for (a = dfui_form_action_get_first(f); a != NULL; a = dfui_action_get_next(a)) { strlcpy(name, dfui_info_get_name(dfui_action_get_info(a)), 70); dfui_debug("creating button `%s' (%d) @ %d / %d\n", name, strlen(name), left_acc, cf->width); /* * Check for overflow. If the next button would appear * off the right side of the form, start putting buttons * on the next row. Or, if this is a menu, always put the * next button on the next line. */ if (is_menu || ((left_acc + strlen(name) + 6) > cf->width && left_acc > 1)) { row_start = center_buttons(cf, row_start, is_menu); cf->height++; left_acc = 1; } w = curses_form_widget_add(cf, left_acc, cf->height, 0, CURSES_BUTTON, name, 0, CURSES_WIDGET_WIDEN); curses_widget_tooltip_set(w, dfui_info_get_short_desc(dfui_action_get_info(a))); accel = dfui_action_property_get(a, "accelerator"); if (strlen(accel) > 0) { if (strcmp(accel, "ESC") == 0) { w->accel = '\e'; } else { w->accel = toupper(accel[0]); } } left_acc += (w->width + 2); w->user_id = -1; w->userdata = a; curses_widget_set_click_cb(w, cb_click_close_form); if (row_start == NULL) row_start = w; } center_buttons(cf, row_start, is_menu); }
int read_data(FILE *f, char *buf, int n) { int bcount; /* counts bytes read */ int br; /* bytes read this pass */ bcount = 0; br = 0; while (bcount < n) { if ((br = fread(buf, 1, n - bcount, f)) > 0) { dfui_debug("READ_BYTES<<%d>>\n", br); bcount += br; buf += br; } else if (br <= 0) { dfui_debug("read_data_error<<%d>>\n", br); return(-1); } } return(bcount); }
int write_data(FILE *f, const char *buf, int n) { int bcount; /* counts bytes written */ int bw; /* bytes written this pass */ bcount = 0; bw = 0; while (bcount < n) { if ((bw = fwrite(buf, 1, n - bcount, f)) > 0) { dfui_debug("WROTE_BYTES<<%d>>\n", bw); bcount += bw; buf += bw; } else if (bw <= 0) { dfui_debug("write_data_error<<%d>>\n", bw); return(-1); } } return(bcount); }
/* * Receive a message from the frontend. * This call is synchronous. * After this call, the NUL-terminated message is available in * c->ebuf. */ dfui_err_t dfui_npipe_be_ll_receive(struct dfui_connection *c) { int length; char *buf; dfui_debug("WAITING<<>>\n"); fread(&length, 4, 1, T_NPIPE(c)->in); dfui_debug("LENGTH<<%d>>\n", length); buf = malloc(length + 1); fread(buf, length, 1, T_NPIPE(c)->in); aura_buffer_set(c->ebuf, buf, length); free(buf); dfui_debug("RECEIVED<<%s>>\n", aura_buffer_buf(c->ebuf)); return(DFUI_SUCCESS); }
/* * Send a NUL-terminated reply to the frontend. */ dfui_err_t dfui_tcp_be_ll_reply(struct dfui_connection *c, const char *fmsg) { int length; dfui_debug("SEND<<%s>>\n", fmsg); length = strlen(fmsg); write_data(T_TCP(c)->stream, (char *)&length, sizeof(length)); write_data(T_TCP(c)->stream, fmsg, length); return(DFUI_SUCCESS); }
dfui_err_t dfui_tcp_fe_connect(struct dfui_connection *c) { struct sockaddr_in servaddr; int server_port; server_port = atoi(c->rendezvous); /* * Create the tcp socket */ while (!T_TCP(c)->is_connected) { errno = 0; if ((T_TCP(c)->connected_sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { return(DFUI_FAILURE); } dfui_debug("CLIENT_SOCKET<<%d>>\n", T_TCP(c)->connected_sd); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(server_port); inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr); if (connect(T_TCP(c)->connected_sd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == 0) { dfui_debug("CONNECTED<<>>\n"); T_TCP(c)->is_connected = 1; } else { dfui_debug("NO_CONNECT<<>>\n"); close(T_TCP(c)->connected_sd); sleep(1); } } /* at this point we should be connected */ T_TCP(c)->stream = fdopen(T_TCP(c)->connected_sd, "r+"); return(DFUI_SUCCESS); }
int curses_form_descriptive_labels_add(struct curses_form *cf, const char *text, unsigned int x, unsigned int y, unsigned int width) { struct curses_widget *w; int done = 0; int pos = 0; char *line; line = aura_malloc(width + 1, "descriptive line"); while (!done) { done = extract_wrapped_line(text, line, width, &pos); dfui_debug("line = `%s', done = %d, width = %d, form width = %d : ", line, done, width, cf->width); w = curses_form_widget_add(cf, x, y++, 0, CURSES_LABEL, line, 0, CURSES_WIDGET_WIDEN); dfui_debug("now %d\n", cf->width); } free(line); return(y); }
/* * Ask for, and subsequently receieve, a message from the backend. * msgtype should be one of the DFUI_FE_MSG_* constants. * This call is synchronous. * After this call, the null-terminated, encoded message is * available in T_TCP(c)->buf. */ dfui_err_t dfui_tcp_fe_ll_request(struct dfui_connection *c, char msgtype, const char *msg) { char *fmsg, *buf; int length, result; /* * First, assert that the connection is open. */ if (c == NULL || T_TCP(c)->connected_sd == -1) return(DFUI_FAILURE); /* * Construct a message. */ fmsg = malloc(strlen(msg) + 2); fmsg[0] = msgtype; strcpy(fmsg + 1, msg); dfui_debug("SEND<<%s>>\n", fmsg); /* * Send a NUL-terminated message to the backend. */ length = strlen(fmsg); result = write_data(T_TCP(c)->stream, (char *)&length, sizeof(length)); dfui_debug("result<<%d>>\n", result); result = write_data(T_TCP(c)->stream, (char *)fmsg, length); dfui_debug("result<<%d>>\n", result); /* * Receive a reply from the backend. * If our message was a READY, this should be a message like PRESENT. * Otherwise it should simply be a READY. */ dfui_debug("WAITING<<>>\n"); result = read_data(T_TCP(c)->stream, (char *)&length, sizeof(length)); dfui_debug("result<<%d>>\n", result); buf = malloc(length + 1); result = read_data(T_TCP(c)->stream, buf, length); dfui_debug("result<<%d>>\n", result); aura_buffer_set(c->ebuf, buf, length); free(buf); dfui_debug("RECV<<%s>>\n", aura_buffer_buf(c->ebuf)); free(fmsg); return(DFUI_SUCCESS); }
/* * Send a NUL-terminated reply to the frontend. */ dfui_err_t dfui_npipe_be_ll_reply(struct dfui_connection *c, const char *fmsg) { int length; dfui_debug("SEND<<%s>>\n", fmsg); length = strlen(fmsg); fwrite(&length, 4, 1, T_NPIPE(c)->out); fwrite(fmsg, length, 1, T_NPIPE(c)->out); return(DFUI_SUCCESS); }
dfui_err_t dfui_npipe_fe_connect(struct dfui_connection *c) { asprintf(&T_NPIPE(c)->in_pipename, "/tmp/dfui.%s.to_fe", c->rendezvous); asprintf(&T_NPIPE(c)->out_pipename, "/tmp/dfui.%s.from_fe", c->rendezvous); dfui_debug("waiting for named pipes...\n"); /* * Wait for named pipes to be created. */ if (!is_named_pipe(T_NPIPE(c)->in_pipename)) { while (!is_named_pipe(T_NPIPE(c)->in_pipename)) { sleep(1); } sleep(1); } dfui_debug("opening inflow pipe...\n"); if ((T_NPIPE(c)->in = fopen(T_NPIPE(c)->in_pipename, "r")) == NULL) { return(DFUI_FAILURE); } dfui_debug("opening outflow pipe...\n"); if ((T_NPIPE(c)->out = fopen(T_NPIPE(c)->out_pipename, "w")) == NULL) { fclose(T_NPIPE(c)->in); return(DFUI_FAILURE); } dfui_debug("making outflow pipe raw...\n"); setvbuf(T_NPIPE(c)->out, NULL, _IONBF, 0); return(DFUI_SUCCESS); }
/* * Connect to the frontend. */ dfui_err_t dfui_npipe_be_start(struct dfui_connection *c) { asprintf(&T_NPIPE(c)->out_pipename, "/tmp/dfui.%s.to_fe", c->rendezvous); asprintf(&T_NPIPE(c)->in_pipename, "/tmp/dfui.%s.from_fe", c->rendezvous); /* * Create the named pipes. */ errno = 0; if (mkfifo(T_NPIPE(c)->in_pipename, 0600) < 0) { if (errno != EEXIST) { warn("mkfifo (to_be)"); return(DFUI_FAILURE); } } errno = 0; if (mkfifo(T_NPIPE(c)->out_pipename, 0600) < 0) { if (errno != EEXIST) { warn("mkfifo (to_fe)"); return(DFUI_FAILURE); } } dfui_debug("opening pipes...\n"); if ((T_NPIPE(c)->out = fopen(T_NPIPE(c)->out_pipename, "w")) == NULL) { return(DFUI_FAILURE); } dfui_debug("opened to_fe pipe\n"); setvbuf(T_NPIPE(c)->out, NULL, _IONBF, 0); if ((T_NPIPE(c)->in = fopen(T_NPIPE(c)->in_pipename, "r")) == NULL) { fclose(T_NPIPE(c)->out); return(DFUI_FAILURE); } dfui_debug("opened to_be pipe\n"); return(DFUI_SUCCESS); }
/* * Receive a message from the frontend. * This call is synchronous. * After this call, the NUL-terminated message is available in * c->ebuf. */ dfui_err_t dfui_tcp_be_ll_receive(struct dfui_connection *c) { int length; char *buf; top: if (!T_TCP(c)->is_connected) { dfui_debug("NOT_CONNECTED,ACCEPTING_ON<<%d>>\n", T_TCP(c)->listen_sd); T_TCP(c)->connected_sd = accept(T_TCP(c)->listen_sd, NULL, NULL); dfui_debug("ACCEPTED<<%d>>\n", T_TCP(c)->connected_sd); T_TCP(c)->stream = fdopen(T_TCP(c)->connected_sd, "r+"); T_TCP(c)->is_connected = 1; } else { dfui_debug("ALREADY_CONNECTED<<>>\n"); } dfui_debug("WAITING<<>>\n"); if (read_data(T_TCP(c)->stream, (char *)&length, sizeof(length)) == -1) { dfui_debug("LOST_THEM<<>>\n"); fclose(T_TCP(c)->stream); T_TCP(c)->is_connected = 0; goto top; } buf = malloc(length + 1); if (read_data(T_TCP(c)->stream, buf, length) == -1) { dfui_debug("LOST_THEM<<>>\n"); fclose(T_TCP(c)->stream); T_TCP(c)->is_connected = 0; goto top; } aura_buffer_set(c->ebuf, buf, length); free(buf); dfui_debug("RECEIVED<<%s>>\n", aura_buffer_buf(c->ebuf)); return(DFUI_SUCCESS); }
static struct curses_form * curses_form_construct_from_dfui_form_single(const struct dfui_form *f) { struct curses_form *cf; struct curses_form_userdata *cfu; const char *min_width_str; unsigned int desc_width, min_width = 0; unsigned int len, max_label_width, total_label_width; unsigned int max_button_width, total_button_width; struct dfui_field *fi; struct dfui_action *a; struct curses_widget *label, *xbox; struct dfui_celldata *cd; const char *value; int is_menu; dfui_debug("-----\nconstructing single form: %s\n", dfui_info_get_name(dfui_form_get_info(f))); is_menu = dfui_form_property_is(f, "role", "menu"); cf = curses_form_new(dfui_info_get_name(dfui_form_get_info(f))); AURA_MALLOC(cfu, curses_form_userdata); cfu->f = f; cf->userdata = cfu; cf->cleanup = 1; set_help(f, cf); /* Calculate offsets for nice positioning of labels and buttons. */ /* * Determine the widths of the widest field and the widest * button, and the total widths of all fields and all buttons. */ max_label_width = 0; total_label_width = 0; max_button_width = 0; total_button_width = 0; for (fi = dfui_form_field_get_first(f); fi != NULL; fi = dfui_field_get_next(fi)) { len = MIN(60, strlen(dfui_info_get_name(dfui_field_get_info(fi)))); if (len > max_label_width) max_label_width = len; total_label_width += (len + 2); } for (a = dfui_form_action_get_first(f); a != NULL; a = dfui_action_get_next(a)) { len = strlen(dfui_info_get_name(dfui_action_get_info(a))); if (len > max_button_width) max_button_width = len; total_button_width += (len + 6); } if (total_label_width > (xmax - 2)) total_label_width = (xmax - 2); /* XXX scroll/wrap? */ /* Take the short description and turn it into a set of labels. */ if ((min_width_str = dfui_form_property_get(f, "minimum_width")) != NULL) min_width = atoi(min_width_str); desc_width = 40; desc_width = MAX(desc_width, min_width); if (is_menu) { desc_width = MAX(desc_width, max_button_width); } else { desc_width = MAX(desc_width, total_button_width); } desc_width = MAX(desc_width, max_label_width); /* XXX + max_field_width */ desc_width = MIN(desc_width, xmax - 4); /* -2 for borders, -2 for spaces */ dfui_debug("min width: %d\n", min_width); dfui_debug("button width: %d\n", total_button_width); dfui_debug("label width: %d\n", total_label_width); dfui_debug("resulting width: %d\n", desc_width); dfui_debug("form width: %d\n", cf->width); cf->height = curses_form_descriptive_labels_add(cf, dfui_info_get_short_desc(dfui_form_get_info(f)), 1, cf->height + 1, desc_width); dfui_debug("form width now: %d\n", cf->width); if (!is_menu) cf->height++; /* * Add one label and one textbox (or other control) to a * curses_form for each field in the dfui_form. Each set of * labels and controls is added one row below the previous set. */ for (fi = dfui_form_field_get_first(f); fi != NULL; fi = dfui_field_get_next(fi)) { label = curses_form_widget_add(cf, 1, cf->height, max_label_width, CURSES_LABEL, dfui_info_get_name(dfui_field_get_info(fi)), 0, 0); cd = dfui_dataset_celldata_find(dfui_form_dataset_get_first(f), dfui_field_get_id(fi)); value = dfui_celldata_get_value(cd); if (dfui_field_property_is(fi, "control", "checkbox")) { xbox = curses_form_widget_add(cf, max_label_width + 3, cf->height, 4, CURSES_CHECKBOX, "", 0, 0); xbox->amount = (value[0] == 'Y' ? 1 : 0); } else { xbox = curses_form_widget_add(cf, max_label_width + 3, cf->height, 20, CURSES_TEXTBOX, value, 256, 0); } curses_widget_tooltip_set(xbox, dfui_info_get_short_desc(dfui_field_get_info(fi))); xbox->user_id = 1; xbox->userdata = fi; if (dfui_field_property_is(fi, "editable", "false")) xbox->editable = 0; if (dfui_field_property_is(fi, "obscured", "true")) xbox->obscured = 1; if (dfui_field_option_get_first(fi) != NULL) { curses_widget_set_click_cb(xbox, cb_click_select_option); } cf->height++; } if (dfui_form_field_get_first(f) != NULL) cf->height++; create_buttons(f, cf, is_menu); cf->height++; curses_form_finalize(cf); return(cf); }
static struct curses_form * curses_form_construct_from_dfui_form_multiple(const struct dfui_form *f) { struct curses_form *cf; struct curses_form_userdata *cfu; const char *min_width_str; unsigned int desc_width, min_width = 0; unsigned int len, max_label_width, total_label_width; unsigned int max_button_width, total_button_width; struct dfui_field *fi; struct dfui_action *a; struct curses_widget *label, *button; struct dfui_dataset *ds; const char *name; int left_acc, top_acc; int row = 1, col = 0, ins_x = 1, is_menu = 0; dfui_debug("-----\nconstructing multiple form: %s\n", dfui_info_get_name(dfui_form_get_info(f))); cf = curses_form_new(dfui_info_get_name(dfui_form_get_info(f))); AURA_MALLOC(cfu, curses_form_userdata); cfu->f = f; cf->userdata = cfu; cf->cleanup = 1; set_help(f, cf); /* Calculate offsets for nice positioning of labels and buttons. */ /* * Determine the widths of the widest field and the widest * button, and the total widths of all fields and all buttons. */ max_label_width = 0; total_label_width = 0; max_button_width = 0; total_button_width = 0; for (fi = dfui_form_field_get_first(f); fi != NULL; fi = dfui_field_get_next(fi)) { len = MIN(60, strlen(dfui_info_get_name(dfui_field_get_info(fi)))); if (len > max_label_width) max_label_width = len; total_label_width += (len + 2); } for (a = dfui_form_action_get_first(f); a != NULL; a = dfui_action_get_next(a)) { len = strlen(dfui_info_get_name(dfui_action_get_info(a))); if (len > max_button_width) max_button_width = len; total_button_width += (len + 6); } /* Take the short description and turn it into a set of labels. */ if ((min_width_str = dfui_form_property_get(f, "minimum_width")) != NULL) min_width = atoi(min_width_str); desc_width = 40; desc_width = MAX(desc_width, min_width); desc_width = MAX(desc_width, total_button_width); desc_width = MAX(desc_width, total_label_width); desc_width = MIN(desc_width, xmax - 3); dfui_debug("min width: %d\n", min_width); dfui_debug("button width: %d\n", total_button_width); dfui_debug("label width: %d\n", total_label_width); dfui_debug("resulting width: %d\n", desc_width); dfui_debug("form width: %d\n", cf->width); cf->height = curses_form_descriptive_labels_add(cf, dfui_info_get_short_desc(dfui_form_get_info(f)), 1, cf->height + 1, desc_width); dfui_debug("form width now: %d\n", cf->width); /* Add the fields. */ top_acc = cf->height + 1; cf->height += dfui_form_dataset_count(f) + 2; /* * Create the widgets for a multiple=true form. For each field * in the form, a label containing the field's name, which serves * as a heading, is created. Underneath these labels, for each * dataset in the form, a row of input widgets (typically textboxes) * is added. Non-action, manipulation buttons are also added to * the right of each row. */ left_acc = 1; for (fi = dfui_form_field_get_first(f); fi != NULL; fi = dfui_field_get_next(fi)) { /* * Create a label to serve as a heading for the column. */ name = dfui_info_get_name(dfui_field_get_info(fi)); label = curses_form_widget_add(cf, left_acc, top_acc, 0, CURSES_LABEL, name, 0, CURSES_WIDGET_WIDEN); cfu->widths[col++] = label->width + 2; left_acc += (label->width + 2); } /* * Create a row of widgets for each dataset. */ top_acc++; for (ds = dfui_form_dataset_get_first(f); ds != NULL; ds = dfui_dataset_get_next(ds)) { ins_x = curses_form_create_widget_row(cf, NULL, ds, 1, top_acc++, row++); } /* * Finally, create an 'Add' button to add a new row * if this is an extensible form. */ if (dfui_form_is_extensible(f)) { button = curses_form_widget_add(cf, ins_x, top_acc, 0, CURSES_BUTTON, "Add", 0, CURSES_WIDGET_WIDEN); button->user_id = row; curses_widget_set_click_cb(button, cb_click_insert_row); cf->height++; } cf->height++; /* Add the buttons. */ create_buttons(f, cf, is_menu); cf->height++; curses_form_finalize(cf); return(cf); }