Sebastian Kuschel reports that pfd_closing can be called for a socket
[u/mdw/putty] / sercfg.c
CommitLineData
d3b85d02 1/*
2 * sercfg.c - the serial-port specific parts of the PuTTY
3 * configuration box. Centralised as cross-platform code because
4 * more than one platform will want to use it, but not part of the
5 * main configuration. The expectation is that each platform's
6 * local config function will call out to ser_setup_config_box() if
7 * it needs to set up the standard serial stuff. (Of course, it can
8 * then apply local tweaks after ser_setup_config_box() returns, if
9 * it needs to.)
10 */
11
12#include <assert.h>
13#include <stdlib.h>
14
15#include "putty.h"
16#include "dialog.h"
17#include "storage.h"
18
19static void serial_parity_handler(union control *ctrl, void *dlg,
20 void *data, int event)
21{
22 static const struct {
23 const char *name;
24 int val;
25 } parities[] = {
26 {"None", SER_PAR_NONE},
27 {"Odd", SER_PAR_ODD},
28 {"Even", SER_PAR_EVEN},
29 {"Mark", SER_PAR_MARK},
30 {"Space", SER_PAR_SPACE},
31 };
640d7387 32 int mask = ctrl->listbox.context.i;
33 int i, j;
4a693cfc 34 Conf *conf = (Conf *)data;
d3b85d02 35
36 if (event == EVENT_REFRESH) {
4a693cfc 37 /* Fetching this once at the start of the function ensures we
38 * remember what the right value is supposed to be when
39 * operations below cause reentrant calls to this function. */
40 int oldparity = conf_get_int(conf, CONF_serparity);
41
d3b85d02 42 dlg_update_start(ctrl, dlg);
43 dlg_listbox_clear(ctrl, dlg);
640d7387 44 for (i = 0; i < lenof(parities); i++) {
45 if (mask & (1 << i))
46 dlg_listbox_addwithid(ctrl, dlg, parities[i].name,
47 parities[i].val);
48 }
49 for (i = j = 0; i < lenof(parities); i++) {
b37f2d5b 50 if (mask & (1 << i)) {
51 if (oldparity == parities[i].val) {
52 dlg_listbox_select(ctrl, dlg, j);
53 break;
54 }
640d7387 55 j++;
b37f2d5b 56 }
57 }
58 if (i == lenof(parities)) { /* an unsupported setting was chosen */
59 dlg_listbox_select(ctrl, dlg, 0);
60 oldparity = SER_PAR_NONE;
640d7387 61 }
d3b85d02 62 dlg_update_done(ctrl, dlg);
4a693cfc 63 conf_set_int(conf, CONF_serparity, oldparity); /* restore */
d3b85d02 64 } else if (event == EVENT_SELCHANGE) {
65 int i = dlg_listbox_index(ctrl, dlg);
66 if (i < 0)
67 i = SER_PAR_NONE;
68 else
69 i = dlg_listbox_getid(ctrl, dlg, i);
4a693cfc 70 conf_set_int(conf, CONF_serparity, i);
d3b85d02 71 }
72}
73
74static void serial_flow_handler(union control *ctrl, void *dlg,
75 void *data, int event)
76{
77 static const struct {
78 const char *name;
79 int val;
80 } flows[] = {
81 {"None", SER_FLOW_NONE},
82 {"XON/XOFF", SER_FLOW_XONXOFF},
83 {"RTS/CTS", SER_FLOW_RTSCTS},
84 {"DSR/DTR", SER_FLOW_DSRDTR},
85 };
640d7387 86 int mask = ctrl->listbox.context.i;
87 int i, j;
4a693cfc 88 Conf *conf = (Conf *)data;
d3b85d02 89
90 if (event == EVENT_REFRESH) {
4a693cfc 91 /* Fetching this once at the start of the function ensures we
92 * remember what the right value is supposed to be when
93 * operations below cause reentrant calls to this function. */
94 int oldflow = conf_get_int(conf, CONF_serflow);
95
d3b85d02 96 dlg_update_start(ctrl, dlg);
97 dlg_listbox_clear(ctrl, dlg);
640d7387 98 for (i = 0; i < lenof(flows); i++) {
99 if (mask & (1 << i))
100 dlg_listbox_addwithid(ctrl, dlg, flows[i].name, flows[i].val);
101 }
102 for (i = j = 0; i < lenof(flows); i++) {
b37f2d5b 103 if (mask & (1 << i)) {
104 if (oldflow == flows[i].val) {
105 dlg_listbox_select(ctrl, dlg, j);
106 break;
107 }
640d7387 108 j++;
b37f2d5b 109 }
110 }
111 if (i == lenof(flows)) { /* an unsupported setting was chosen */
112 dlg_listbox_select(ctrl, dlg, 0);
113 oldflow = SER_FLOW_NONE;
640d7387 114 }
d3b85d02 115 dlg_update_done(ctrl, dlg);
4a693cfc 116 conf_set_int(conf, CONF_serflow, oldflow);/* restore */
d3b85d02 117 } else if (event == EVENT_SELCHANGE) {
118 int i = dlg_listbox_index(ctrl, dlg);
119 if (i < 0)
b37f2d5b 120 i = SER_FLOW_NONE;
d3b85d02 121 else
122 i = dlg_listbox_getid(ctrl, dlg, i);
4a693cfc 123 conf_set_int(conf, CONF_serflow, i);
d3b85d02 124 }
125}
126
640d7387 127void ser_setup_config_box(struct controlbox *b, int midsession,
128 int parity_mask, int flow_mask)
d3b85d02 129{
130 struct controlset *s;
131 union control *c;
132
bb2a7ca9 133 if (!midsession) {
d3b85d02 134 int i;
135 extern void config_protocolbuttons_handler(union control *, void *,
136 void *, int);
bb2a7ca9 137
138 /*
139 * Add the serial back end to the protocols list at the
140 * top of the config box.
141 */
142 s = ctrl_getset(b, "Session", "hostport",
143 "Specify the destination you want to connect to");
144
d3b85d02 145 for (i = 0; i < s->ncontrols; i++) {
146 c = s->ctrls[i];
147 if (c->generic.type == CTRL_RADIO &&
148 c->generic.handler == config_protocolbuttons_handler) {
149 c->radio.nbuttons++;
150 c->radio.ncolumns++;
151 c->radio.buttons =
152 sresize(c->radio.buttons, c->radio.nbuttons, char *);
153 c->radio.buttons[c->radio.nbuttons-1] =
154 dupstr("Serial");
155 c->radio.buttondata =
156 sresize(c->radio.buttondata, c->radio.nbuttons, intorptr);
157 c->radio.buttondata[c->radio.nbuttons-1] = I(PROT_SERIAL);
158 if (c->radio.shortcuts) {
159 c->radio.shortcuts =
160 sresize(c->radio.shortcuts, c->radio.nbuttons, char);
063f6c96 161 c->radio.shortcuts[c->radio.nbuttons-1] = 'r';
d3b85d02 162 }
163 }
164 }
165 }
166
167 /*
168 * Entirely new Connection/Serial panel for serial port
169 * configuration.
170 */
171 ctrl_settitle(b, "Connection/Serial",
172 "Options controlling local serial lines");
173
174 if (!midsession) {
175 /*
176 * We don't permit switching to a different serial port in
177 * midflight, although we do allow all other
178 * reconfiguration.
179 */
180 s = ctrl_getset(b, "Connection/Serial", "serline",
181 "Select a serial line");
182 ctrl_editbox(s, "Serial line to connect to", 'l', 40,
183 HELPCTX(serial_line),
4a693cfc 184 conf_editbox_handler, I(CONF_serline), I(1));
d3b85d02 185 }
186
187 s = ctrl_getset(b, "Connection/Serial", "sercfg", "Configure the serial line");
188 ctrl_editbox(s, "Speed (baud)", 's', 40,
189 HELPCTX(serial_speed),
4a693cfc 190 conf_editbox_handler, I(CONF_serspeed), I(-1));
d3b85d02 191 ctrl_editbox(s, "Data bits", 'b', 40,
192 HELPCTX(serial_databits),
4a693cfc 193 conf_editbox_handler, I(CONF_serdatabits), I(-1));
d3b85d02 194 /*
195 * Stop bits come in units of one half.
196 */
197 ctrl_editbox(s, "Stop bits", 't', 40,
198 HELPCTX(serial_stopbits),
4a693cfc 199 conf_editbox_handler, I(CONF_serstopbits), I(-2));
d3b85d02 200 ctrl_droplist(s, "Parity", 'p', 40,
201 HELPCTX(serial_parity),
640d7387 202 serial_parity_handler, I(parity_mask));
d3b85d02 203 ctrl_droplist(s, "Flow control", 'f', 40,
204 HELPCTX(serial_flow),
640d7387 205 serial_flow_handler, I(flow_mask));
d3b85d02 206}