]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - sercfg.c
first pass
[PuTTY.git] / sercfg.c
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
19 static 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     };
32     int mask = ctrl->listbox.context.i;
33     int i, j;
34     Conf *conf = (Conf *)data;
35
36     if (event == EVENT_REFRESH) {
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
42         dlg_update_start(ctrl, dlg);
43         dlg_listbox_clear(ctrl, dlg);
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++) {
50             if (mask & (1 << i)) {
51                 if (oldparity == parities[i].val) {
52                     dlg_listbox_select(ctrl, dlg, j);
53                     break;
54                 }
55                 j++;
56             }
57         }
58         if (i == lenof(parities)) {    /* an unsupported setting was chosen */
59             dlg_listbox_select(ctrl, dlg, 0);
60             oldparity = SER_PAR_NONE;
61         }
62         dlg_update_done(ctrl, dlg);
63         conf_set_int(conf, CONF_serparity, oldparity);    /* restore */
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);
70         conf_set_int(conf, CONF_serparity, i);
71     }
72 }
73
74 static 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     };
86     int mask = ctrl->listbox.context.i;
87     int i, j;
88     Conf *conf = (Conf *)data;
89
90     if (event == EVENT_REFRESH) {
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
96         dlg_update_start(ctrl, dlg);
97         dlg_listbox_clear(ctrl, dlg);
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++) {
103             if (mask & (1 << i)) {
104                 if (oldflow == flows[i].val) {
105                     dlg_listbox_select(ctrl, dlg, j);
106                     break;
107                 }
108                 j++;
109             }
110         }
111         if (i == lenof(flows)) {       /* an unsupported setting was chosen */
112             dlg_listbox_select(ctrl, dlg, 0);
113             oldflow = SER_FLOW_NONE;
114         }
115         dlg_update_done(ctrl, dlg);
116         conf_set_int(conf, CONF_serflow, oldflow);/* restore */
117     } else if (event == EVENT_SELCHANGE) {
118         int i = dlg_listbox_index(ctrl, dlg);
119         if (i < 0)
120             i = SER_FLOW_NONE;
121         else
122             i = dlg_listbox_getid(ctrl, dlg, i);
123         conf_set_int(conf, CONF_serflow, i);
124     }
125 }
126
127 void ser_setup_config_box(struct controlbox *b, int midsession,
128                           int parity_mask, int flow_mask)
129 {
130     struct controlset *s;
131     union control *c;
132
133     if (!midsession) {
134         int i;
135         extern void config_protocolbuttons_handler(union control *, void *,
136                                                    void *, int);
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
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);
161                     c->radio.shortcuts[c->radio.nbuttons-1] = 'r';
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),
184                      conf_editbox_handler, I(CONF_serline), I(1));
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),
190                  conf_editbox_handler, I(CONF_serspeed), I(-1));
191     ctrl_editbox(s, "Data bits", 'b', 40,
192                  HELPCTX(serial_databits),
193                  conf_editbox_handler, I(CONF_serdatabits), I(-1));
194     /*
195      * Stop bits come in units of one half.
196      */
197     ctrl_editbox(s, "Stop bits", 't', 40,
198                  HELPCTX(serial_stopbits),
199                  conf_editbox_handler, I(CONF_serstopbits), I(-2));
200     ctrl_droplist(s, "Parity", 'p', 40,
201                   HELPCTX(serial_parity),
202                   serial_parity_handler, I(parity_mask));
203     ctrl_droplist(s, "Flow control", 'f', 40,
204                   HELPCTX(serial_flow),
205                   serial_flow_handler, I(flow_mask));
206 }