config.c 88 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691
  1. /*
  2. * config.c - the platform-independent parts of the PuTTY
  3. * configuration box.
  4. */
  5. #include <assert.h>
  6. #include <stdlib.h>
  7. #include "putty.h"
  8. #include "dialog.h"
  9. #include "storage.h"
  10. #define PRINTER_DISABLED_STRING "None (printing disabled)"
  11. #define HOST_BOX_TITLE "Host Name (or IP address)"
  12. #define PORT_BOX_TITLE "Port"
  13. void conf_radiobutton_handler(union control *ctrl, void *dlg,
  14. void *data, int event)
  15. {
  16. int button;
  17. Conf *conf = (Conf *)data;
  18. /*
  19. * For a standard radio button set, the context parameter gives
  20. * the primary key (CONF_foo), and the extra data per button
  21. * gives the value the target field should take if that button
  22. * is the one selected.
  23. */
  24. if (event == EVENT_REFRESH) {
  25. int val = conf_get_int(conf, ctrl->radio.context.i);
  26. for (button = 0; button < ctrl->radio.nbuttons; button++)
  27. if (val == ctrl->radio.buttondata[button].i)
  28. break;
  29. /* We expected that `break' to happen, in all circumstances. */
  30. assert(button < ctrl->radio.nbuttons);
  31. dlg_radiobutton_set(ctrl, dlg, button);
  32. } else if (event == EVENT_VALCHANGE) {
  33. button = dlg_radiobutton_get(ctrl, dlg);
  34. assert(button >= 0 && button < ctrl->radio.nbuttons);
  35. conf_set_int(conf, ctrl->radio.context.i,
  36. ctrl->radio.buttondata[button].i);
  37. }
  38. }
  39. #define CHECKBOX_INVERT (1<<30)
  40. void conf_checkbox_handler(union control *ctrl, void *dlg,
  41. void *data, int event)
  42. {
  43. int key, invert;
  44. Conf *conf = (Conf *)data;
  45. /*
  46. * For a standard checkbox, the context parameter gives the
  47. * primary key (CONF_foo), optionally ORed with CHECKBOX_INVERT.
  48. */
  49. key = ctrl->checkbox.context.i;
  50. if (key & CHECKBOX_INVERT) {
  51. key &= ~CHECKBOX_INVERT;
  52. invert = 1;
  53. } else
  54. invert = 0;
  55. /*
  56. * C lacks a logical XOR, so the following code uses the idiom
  57. * (!a ^ !b) to obtain the logical XOR of a and b. (That is, 1
  58. * iff exactly one of a and b is nonzero, otherwise 0.)
  59. */
  60. if (event == EVENT_REFRESH) {
  61. int val = conf_get_int(conf, key);
  62. dlg_checkbox_set(ctrl, dlg, (!val ^ !invert));
  63. } else if (event == EVENT_VALCHANGE) {
  64. conf_set_int(conf, key, !dlg_checkbox_get(ctrl,dlg) ^ !invert);
  65. }
  66. }
  67. void conf_editbox_handler(union control *ctrl, void *dlg,
  68. void *data, int event)
  69. {
  70. /*
  71. * The standard edit-box handler expects the main `context'
  72. * field to contain the primary key. The secondary `context2'
  73. * field indicates the type of this field:
  74. *
  75. * - if context2 > 0, the field is a string.
  76. * - if context2 == -1, the field is an int and the edit box
  77. * is numeric.
  78. * - if context2 < -1, the field is an int and the edit box is
  79. * _floating_, and (-context2) gives the scale. (E.g. if
  80. * context2 == -1000, then typing 1.2 into the box will set
  81. * the field to 1200.)
  82. */
  83. int key = ctrl->editbox.context.i;
  84. int length = ctrl->editbox.context2.i;
  85. Conf *conf = (Conf *)data;
  86. if (length > 0) {
  87. if (event == EVENT_REFRESH) {
  88. char *field = conf_get_str(conf, key);
  89. dlg_editbox_set(ctrl, dlg, field);
  90. } else if (event == EVENT_VALCHANGE) {
  91. char *field = dlg_editbox_get(ctrl, dlg);
  92. conf_set_str(conf, key, field);
  93. sfree(field);
  94. }
  95. } else if (length < 0) {
  96. if (event == EVENT_REFRESH) {
  97. char str[80];
  98. int value = conf_get_int(conf, key);
  99. if (length == -1)
  100. sprintf(str, "%d", value);
  101. else
  102. sprintf(str, "%g", (double)value / (double)(-length));
  103. dlg_editbox_set(ctrl, dlg, str);
  104. } else if (event == EVENT_VALCHANGE) {
  105. char *str = dlg_editbox_get(ctrl, dlg);
  106. if (length == -1)
  107. conf_set_int(conf, key, atoi(str));
  108. else
  109. conf_set_int(conf, key, (int)((-length) * atof(str)));
  110. sfree(str);
  111. }
  112. }
  113. }
  114. void conf_filesel_handler(union control *ctrl, void *dlg,
  115. void *data, int event)
  116. {
  117. int key = ctrl->fileselect.context.i;
  118. Conf *conf = (Conf *)data;
  119. if (event == EVENT_REFRESH) {
  120. dlg_filesel_set(ctrl, dlg, conf_get_filename(conf, key));
  121. } else if (event == EVENT_VALCHANGE) {
  122. Filename *filename = dlg_filesel_get(ctrl, dlg);
  123. conf_set_filename(conf, key, filename);
  124. filename_free(filename);
  125. }
  126. }
  127. void conf_fontsel_handler(union control *ctrl, void *dlg,
  128. void *data, int event)
  129. {
  130. int key = ctrl->fontselect.context.i;
  131. Conf *conf = (Conf *)data;
  132. if (event == EVENT_REFRESH) {
  133. dlg_fontsel_set(ctrl, dlg, conf_get_fontspec(conf, key));
  134. } else if (event == EVENT_VALCHANGE) {
  135. FontSpec *fontspec = dlg_fontsel_get(ctrl, dlg);
  136. conf_set_fontspec(conf, key, fontspec);
  137. fontspec_free(fontspec);
  138. }
  139. }
  140. static void config_host_handler(union control *ctrl, void *dlg,
  141. void *data, int event)
  142. {
  143. Conf *conf = (Conf *)data;
  144. /*
  145. * This function works just like the standard edit box handler,
  146. * only it has to choose the control's label and text from two
  147. * different places depending on the protocol.
  148. */
  149. if (event == EVENT_REFRESH) {
  150. if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL) {
  151. /*
  152. * This label text is carefully chosen to contain an n,
  153. * since that's the shortcut for the host name control.
  154. */
  155. dlg_label_change(ctrl, dlg, "Serial line");
  156. dlg_editbox_set(ctrl, dlg, conf_get_str(conf, CONF_serline));
  157. } else {
  158. dlg_label_change(ctrl, dlg, HOST_BOX_TITLE);
  159. dlg_editbox_set(ctrl, dlg, conf_get_str(conf, CONF_host));
  160. }
  161. } else if (event == EVENT_VALCHANGE) {
  162. char *s = dlg_editbox_get(ctrl, dlg);
  163. if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL)
  164. conf_set_str(conf, CONF_serline, s);
  165. else
  166. conf_set_str(conf, CONF_host, s);
  167. sfree(s);
  168. }
  169. }
  170. static void config_port_handler(union control *ctrl, void *dlg,
  171. void *data, int event)
  172. {
  173. Conf *conf = (Conf *)data;
  174. char buf[80];
  175. /*
  176. * This function works similarly to the standard edit box handler,
  177. * only it has to choose the control's label and text from two
  178. * different places depending on the protocol.
  179. */
  180. if (event == EVENT_REFRESH) {
  181. if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL) {
  182. /*
  183. * This label text is carefully chosen to contain a p,
  184. * since that's the shortcut for the port control.
  185. */
  186. dlg_label_change(ctrl, dlg, "Speed");
  187. sprintf(buf, "%d", conf_get_int(conf, CONF_serspeed));
  188. } else {
  189. dlg_label_change(ctrl, dlg, PORT_BOX_TITLE);
  190. if (conf_get_int(conf, CONF_port) != 0)
  191. sprintf(buf, "%d", conf_get_int(conf, CONF_port));
  192. else
  193. /* Display an (invalid) port of 0 as blank */
  194. buf[0] = '\0';
  195. }
  196. dlg_editbox_set(ctrl, dlg, buf);
  197. } else if (event == EVENT_VALCHANGE) {
  198. char *s = dlg_editbox_get(ctrl, dlg);
  199. int i = atoi(s);
  200. sfree(s);
  201. if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL)
  202. conf_set_int(conf, CONF_serspeed, i);
  203. else
  204. conf_set_int(conf, CONF_port, i);
  205. }
  206. }
  207. struct hostport {
  208. union control *host, *port;
  209. };
  210. /*
  211. * We export this function so that platform-specific config
  212. * routines can use it to conveniently identify the protocol radio
  213. * buttons in order to add to them.
  214. */
  215. void config_protocolbuttons_handler(union control *ctrl, void *dlg,
  216. void *data, int event)
  217. {
  218. int button;
  219. Conf *conf = (Conf *)data;
  220. struct hostport *hp = (struct hostport *)ctrl->radio.context.p;
  221. /*
  222. * This function works just like the standard radio-button
  223. * handler, except that it also has to change the setting of
  224. * the port box, and refresh both host and port boxes when. We
  225. * expect the context parameter to point at a hostport
  226. * structure giving the `union control's for both.
  227. */
  228. if (event == EVENT_REFRESH) {
  229. int protocol = conf_get_int(conf, CONF_protocol);
  230. for (button = 0; button < ctrl->radio.nbuttons; button++)
  231. if (protocol == ctrl->radio.buttondata[button].i)
  232. break;
  233. /* We expected that `break' to happen, in all circumstances. */
  234. assert(button < ctrl->radio.nbuttons);
  235. dlg_radiobutton_set(ctrl, dlg, button);
  236. } else if (event == EVENT_VALCHANGE) {
  237. int oldproto = conf_get_int(conf, CONF_protocol);
  238. int newproto, port;
  239. button = dlg_radiobutton_get(ctrl, dlg);
  240. assert(button >= 0 && button < ctrl->radio.nbuttons);
  241. newproto = ctrl->radio.buttondata[button].i;
  242. conf_set_int(conf, CONF_protocol, newproto);
  243. if (oldproto != newproto) {
  244. Backend *ob = backend_from_proto(oldproto);
  245. Backend *nb = backend_from_proto(newproto);
  246. assert(ob);
  247. assert(nb);
  248. /* Iff the user hasn't changed the port from the old protocol's
  249. * default, update it with the new protocol's default.
  250. * (This includes a "default" of 0, implying that there is no
  251. * sensible default for that protocol; in this case it's
  252. * displayed as a blank.)
  253. * This helps with the common case of tabbing through the
  254. * controls in order and setting a non-default port before
  255. * getting to the protocol; we want that non-default port
  256. * to be preserved. */
  257. port = conf_get_int(conf, CONF_port);
  258. if (port == ob->default_port)
  259. conf_set_int(conf, CONF_port, nb->default_port);
  260. }
  261. dlg_refresh(hp->host, dlg);
  262. dlg_refresh(hp->port, dlg);
  263. }
  264. }
  265. static void loggingbuttons_handler(union control *ctrl, void *dlg,
  266. void *data, int event)
  267. {
  268. int button;
  269. Conf *conf = (Conf *)data;
  270. /* This function works just like the standard radio-button handler,
  271. * but it has to fall back to "no logging" in situations where the
  272. * configured logging type isn't applicable.
  273. */
  274. if (event == EVENT_REFRESH) {
  275. int logtype = conf_get_int(conf, CONF_logtype);
  276. for (button = 0; button < ctrl->radio.nbuttons; button++)
  277. if (logtype == ctrl->radio.buttondata[button].i)
  278. break;
  279. /* We fell off the end, so we lack the configured logging type */
  280. if (button == ctrl->radio.nbuttons) {
  281. button = 0;
  282. conf_set_int(conf, CONF_logtype, LGTYP_NONE);
  283. }
  284. dlg_radiobutton_set(ctrl, dlg, button);
  285. } else if (event == EVENT_VALCHANGE) {
  286. button = dlg_radiobutton_get(ctrl, dlg);
  287. assert(button >= 0 && button < ctrl->radio.nbuttons);
  288. conf_set_int(conf, CONF_logtype, ctrl->radio.buttondata[button].i);
  289. }
  290. }
  291. static void numeric_keypad_handler(union control *ctrl, void *dlg,
  292. void *data, int event)
  293. {
  294. int button;
  295. Conf *conf = (Conf *)data;
  296. /*
  297. * This function works much like the standard radio button
  298. * handler, but it has to handle two fields in Conf.
  299. */
  300. if (event == EVENT_REFRESH) {
  301. if (conf_get_int(conf, CONF_nethack_keypad))
  302. button = 2;
  303. else if (conf_get_int(conf, CONF_app_keypad))
  304. button = 1;
  305. else
  306. button = 0;
  307. assert(button < ctrl->radio.nbuttons);
  308. dlg_radiobutton_set(ctrl, dlg, button);
  309. } else if (event == EVENT_VALCHANGE) {
  310. button = dlg_radiobutton_get(ctrl, dlg);
  311. assert(button >= 0 && button < ctrl->radio.nbuttons);
  312. if (button == 2) {
  313. conf_set_int(conf, CONF_app_keypad, FALSE);
  314. conf_set_int(conf, CONF_nethack_keypad, TRUE);
  315. } else {
  316. conf_set_int(conf, CONF_app_keypad, (button != 0));
  317. conf_set_int(conf, CONF_nethack_keypad, FALSE);
  318. }
  319. }
  320. }
  321. static void cipherlist_handler(union control *ctrl, void *dlg,
  322. void *data, int event)
  323. {
  324. Conf *conf = (Conf *)data;
  325. if (event == EVENT_REFRESH) {
  326. int i;
  327. static const struct { const char *s; int c; } ciphers[] = {
  328. { "ChaCha20 (SSH-2 only)", CIPHER_CHACHA20 },
  329. { "3DES", CIPHER_3DES },
  330. { "Blowfish", CIPHER_BLOWFISH },
  331. { "DES", CIPHER_DES },
  332. { "AES (SSH-2 only)", CIPHER_AES },
  333. { "Arcfour (SSH-2 only)", CIPHER_ARCFOUR },
  334. { "-- warn below here --", CIPHER_WARN }
  335. };
  336. /* Set up the "selected ciphers" box. */
  337. /* (cipherlist assumed to contain all ciphers) */
  338. dlg_update_start(ctrl, dlg);
  339. dlg_listbox_clear(ctrl, dlg);
  340. for (i = 0; i < CIPHER_MAX; i++) {
  341. int c = conf_get_int_int(conf, CONF_ssh_cipherlist, i);
  342. int j;
  343. const char *cstr = NULL;
  344. for (j = 0; j < (sizeof ciphers) / (sizeof ciphers[0]); j++) {
  345. if (ciphers[j].c == c) {
  346. cstr = ciphers[j].s;
  347. break;
  348. }
  349. }
  350. dlg_listbox_addwithid(ctrl, dlg, cstr, c);
  351. }
  352. dlg_update_done(ctrl, dlg);
  353. } else if (event == EVENT_VALCHANGE) {
  354. int i;
  355. /* Update array to match the list box. */
  356. for (i=0; i < CIPHER_MAX; i++)
  357. conf_set_int_int(conf, CONF_ssh_cipherlist, i,
  358. dlg_listbox_getid(ctrl, dlg, i));
  359. }
  360. }
  361. #ifndef NO_GSSAPI
  362. static void gsslist_handler(union control *ctrl, void *dlg,
  363. void *data, int event)
  364. {
  365. Conf *conf = (Conf *)data;
  366. if (event == EVENT_REFRESH) {
  367. int i;
  368. dlg_update_start(ctrl, dlg);
  369. dlg_listbox_clear(ctrl, dlg);
  370. for (i = 0; i < ngsslibs; i++) {
  371. int id = conf_get_int_int(conf, CONF_ssh_gsslist, i);
  372. assert(id >= 0 && id < ngsslibs);
  373. dlg_listbox_addwithid(ctrl, dlg, gsslibnames[id], id);
  374. }
  375. dlg_update_done(ctrl, dlg);
  376. } else if (event == EVENT_VALCHANGE) {
  377. int i;
  378. /* Update array to match the list box. */
  379. for (i=0; i < ngsslibs; i++)
  380. conf_set_int_int(conf, CONF_ssh_gsslist, i,
  381. dlg_listbox_getid(ctrl, dlg, i));
  382. }
  383. }
  384. #endif
  385. static void kexlist_handler(union control *ctrl, void *dlg,
  386. void *data, int event)
  387. {
  388. Conf *conf = (Conf *)data;
  389. if (event == EVENT_REFRESH) {
  390. int i;
  391. static const struct { const char *s; int k; } kexes[] = {
  392. { "Diffie-Hellman group 1", KEX_DHGROUP1 },
  393. { "Diffie-Hellman group 14", KEX_DHGROUP14 },
  394. { "Diffie-Hellman group exchange", KEX_DHGEX },
  395. { "RSA-based key exchange", KEX_RSA },
  396. { "ECDH key exchange", KEX_ECDH },
  397. { "-- warn below here --", KEX_WARN }
  398. };
  399. /* Set up the "kex preference" box. */
  400. /* (kexlist assumed to contain all algorithms) */
  401. dlg_update_start(ctrl, dlg);
  402. dlg_listbox_clear(ctrl, dlg);
  403. for (i = 0; i < KEX_MAX; i++) {
  404. int k = conf_get_int_int(conf, CONF_ssh_kexlist, i);
  405. int j;
  406. const char *kstr = NULL;
  407. for (j = 0; j < (sizeof kexes) / (sizeof kexes[0]); j++) {
  408. if (kexes[j].k == k) {
  409. kstr = kexes[j].s;
  410. break;
  411. }
  412. }
  413. dlg_listbox_addwithid(ctrl, dlg, kstr, k);
  414. }
  415. dlg_update_done(ctrl, dlg);
  416. } else if (event == EVENT_VALCHANGE) {
  417. int i;
  418. /* Update array to match the list box. */
  419. for (i=0; i < KEX_MAX; i++)
  420. conf_set_int_int(conf, CONF_ssh_kexlist, i,
  421. dlg_listbox_getid(ctrl, dlg, i));
  422. }
  423. }
  424. static void hklist_handler(union control *ctrl, void *dlg,
  425. void *data, int event)
  426. {
  427. Conf *conf = (Conf *)data;
  428. if (event == EVENT_REFRESH) {
  429. int i;
  430. static const struct { const char *s; int k; } hks[] = {
  431. { "Ed25519", HK_ED25519 },
  432. { "ECDSA", HK_ECDSA },
  433. { "DSA", HK_DSA },
  434. { "RSA", HK_RSA },
  435. { "-- warn below here --", HK_WARN }
  436. };
  437. /* Set up the "host key preference" box. */
  438. /* (hklist assumed to contain all algorithms) */
  439. dlg_update_start(ctrl, dlg);
  440. dlg_listbox_clear(ctrl, dlg);
  441. for (i = 0; i < HK_MAX; i++) {
  442. int k = conf_get_int_int(conf, CONF_ssh_hklist, i);
  443. int j;
  444. const char *kstr = NULL;
  445. for (j = 0; j < lenof(hks); j++) {
  446. if (hks[j].k == k) {
  447. kstr = hks[j].s;
  448. break;
  449. }
  450. }
  451. dlg_listbox_addwithid(ctrl, dlg, kstr, k);
  452. }
  453. dlg_update_done(ctrl, dlg);
  454. } else if (event == EVENT_VALCHANGE) {
  455. int i;
  456. /* Update array to match the list box. */
  457. for (i=0; i < HK_MAX; i++)
  458. conf_set_int_int(conf, CONF_ssh_hklist, i,
  459. dlg_listbox_getid(ctrl, dlg, i));
  460. }
  461. }
  462. static void printerbox_handler(union control *ctrl, void *dlg,
  463. void *data, int event)
  464. {
  465. Conf *conf = (Conf *)data;
  466. if (event == EVENT_REFRESH) {
  467. int nprinters, i;
  468. printer_enum *pe;
  469. const char *printer;
  470. dlg_update_start(ctrl, dlg);
  471. /*
  472. * Some backends may wish to disable the drop-down list on
  473. * this edit box. Be prepared for this.
  474. */
  475. if (ctrl->editbox.has_list) {
  476. dlg_listbox_clear(ctrl, dlg);
  477. dlg_listbox_add(ctrl, dlg, PRINTER_DISABLED_STRING);
  478. pe = printer_start_enum(&nprinters);
  479. for (i = 0; i < nprinters; i++)
  480. dlg_listbox_add(ctrl, dlg, printer_get_name(pe, i));
  481. printer_finish_enum(pe);
  482. }
  483. printer = conf_get_str(conf, CONF_printer);
  484. if (!printer)
  485. printer = PRINTER_DISABLED_STRING;
  486. dlg_editbox_set(ctrl, dlg, printer);
  487. dlg_update_done(ctrl, dlg);
  488. } else if (event == EVENT_VALCHANGE) {
  489. char *printer = dlg_editbox_get(ctrl, dlg);
  490. if (!strcmp(printer, PRINTER_DISABLED_STRING))
  491. printer[0] = '\0';
  492. conf_set_str(conf, CONF_printer, printer);
  493. sfree(printer);
  494. }
  495. }
  496. static void codepage_handler(union control *ctrl, void *dlg,
  497. void *data, int event)
  498. {
  499. Conf *conf = (Conf *)data;
  500. if (event == EVENT_REFRESH) {
  501. int i;
  502. const char *cp, *thiscp;
  503. dlg_update_start(ctrl, dlg);
  504. thiscp = cp_name(decode_codepage(conf_get_str(conf,
  505. CONF_line_codepage)));
  506. dlg_listbox_clear(ctrl, dlg);
  507. for (i = 0; (cp = cp_enumerate(i)) != NULL; i++)
  508. dlg_listbox_add(ctrl, dlg, cp);
  509. dlg_editbox_set(ctrl, dlg, thiscp);
  510. conf_set_str(conf, CONF_line_codepage, thiscp);
  511. dlg_update_done(ctrl, dlg);
  512. } else if (event == EVENT_VALCHANGE) {
  513. char *codepage = dlg_editbox_get(ctrl, dlg);
  514. conf_set_str(conf, CONF_line_codepage,
  515. cp_name(decode_codepage(codepage)));
  516. sfree(codepage);
  517. }
  518. }
  519. static void sshbug_handler(union control *ctrl, void *dlg,
  520. void *data, int event)
  521. {
  522. Conf *conf = (Conf *)data;
  523. if (event == EVENT_REFRESH) {
  524. /*
  525. * We must fetch the previously configured value from the Conf
  526. * before we start modifying the drop-down list, otherwise the
  527. * spurious SELCHANGE we trigger in the process will overwrite
  528. * the value we wanted to keep.
  529. */
  530. int oldconf = conf_get_int(conf, ctrl->listbox.context.i);
  531. dlg_update_start(ctrl, dlg);
  532. dlg_listbox_clear(ctrl, dlg);
  533. dlg_listbox_addwithid(ctrl, dlg, "Auto", AUTO);
  534. dlg_listbox_addwithid(ctrl, dlg, "Off", FORCE_OFF);
  535. dlg_listbox_addwithid(ctrl, dlg, "On", FORCE_ON);
  536. switch (oldconf) {
  537. case AUTO: dlg_listbox_select(ctrl, dlg, 0); break;
  538. case FORCE_OFF: dlg_listbox_select(ctrl, dlg, 1); break;
  539. case FORCE_ON: dlg_listbox_select(ctrl, dlg, 2); break;
  540. }
  541. dlg_update_done(ctrl, dlg);
  542. } else if (event == EVENT_SELCHANGE) {
  543. int i = dlg_listbox_index(ctrl, dlg);
  544. if (i < 0)
  545. i = AUTO;
  546. else
  547. i = dlg_listbox_getid(ctrl, dlg, i);
  548. conf_set_int(conf, ctrl->listbox.context.i, i);
  549. }
  550. }
  551. struct sessionsaver_data {
  552. union control *editbox, *listbox, *loadbutton, *savebutton, *delbutton;
  553. union control *okbutton, *cancelbutton;
  554. struct sesslist sesslist;
  555. int midsession;
  556. char *savedsession; /* the current contents of ssd->editbox */
  557. };
  558. static void sessionsaver_data_free(void *ssdv)
  559. {
  560. struct sessionsaver_data *ssd = (struct sessionsaver_data *)ssdv;
  561. get_sesslist(&ssd->sesslist, FALSE);
  562. sfree(ssd->savedsession);
  563. sfree(ssd);
  564. }
  565. /*
  566. * Helper function to load the session selected in the list box, if
  567. * any, as this is done in more than one place below. Returns 0 for
  568. * failure.
  569. */
  570. static int load_selected_session(struct sessionsaver_data *ssd,
  571. void *dlg, Conf *conf, int *maybe_launch)
  572. {
  573. int i = dlg_listbox_index(ssd->listbox, dlg);
  574. int isdef;
  575. if (i < 0) {
  576. dlg_beep(dlg);
  577. return 0;
  578. }
  579. isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings");
  580. load_settings(ssd->sesslist.sessions[i], conf);
  581. sfree(ssd->savedsession);
  582. ssd->savedsession = dupstr(isdef ? "" : ssd->sesslist.sessions[i]);
  583. if (maybe_launch)
  584. *maybe_launch = !isdef;
  585. dlg_refresh(NULL, dlg);
  586. /* Restore the selection, which might have been clobbered by
  587. * changing the value of the edit box. */
  588. dlg_listbox_select(ssd->listbox, dlg, i);
  589. return 1;
  590. }
  591. static void sessionsaver_handler(union control *ctrl, void *dlg,
  592. void *data, int event)
  593. {
  594. Conf *conf = (Conf *)data;
  595. struct sessionsaver_data *ssd =
  596. (struct sessionsaver_data *)ctrl->generic.context.p;
  597. if (event == EVENT_REFRESH) {
  598. if (ctrl == ssd->editbox) {
  599. dlg_editbox_set(ctrl, dlg, ssd->savedsession);
  600. } else if (ctrl == ssd->listbox) {
  601. int i;
  602. dlg_update_start(ctrl, dlg);
  603. dlg_listbox_clear(ctrl, dlg);
  604. for (i = 0; i < ssd->sesslist.nsessions; i++)
  605. dlg_listbox_add(ctrl, dlg, ssd->sesslist.sessions[i]);
  606. dlg_update_done(ctrl, dlg);
  607. }
  608. } else if (event == EVENT_VALCHANGE) {
  609. int top, bottom, halfway, i;
  610. if (ctrl == ssd->editbox) {
  611. sfree(ssd->savedsession);
  612. ssd->savedsession = dlg_editbox_get(ctrl, dlg);
  613. top = ssd->sesslist.nsessions;
  614. bottom = -1;
  615. while (top-bottom > 1) {
  616. halfway = (top+bottom)/2;
  617. i = strcmp(ssd->savedsession, ssd->sesslist.sessions[halfway]);
  618. if (i <= 0 ) {
  619. top = halfway;
  620. } else {
  621. bottom = halfway;
  622. }
  623. }
  624. if (top == ssd->sesslist.nsessions) {
  625. top -= 1;
  626. }
  627. dlg_listbox_select(ssd->listbox, dlg, top);
  628. }
  629. } else if (event == EVENT_ACTION) {
  630. int mbl = FALSE;
  631. if (!ssd->midsession &&
  632. (ctrl == ssd->listbox ||
  633. (ssd->loadbutton && ctrl == ssd->loadbutton))) {
  634. /*
  635. * The user has double-clicked a session, or hit Load.
  636. * We must load the selected session, and then
  637. * terminate the configuration dialog _if_ there was a
  638. * double-click on the list box _and_ that session
  639. * contains a hostname.
  640. */
  641. if (load_selected_session(ssd, dlg, conf, &mbl) &&
  642. (mbl && ctrl == ssd->listbox && conf_launchable(conf))) {
  643. dlg_end(dlg, 1); /* it's all over, and succeeded */
  644. }
  645. } else if (ctrl == ssd->savebutton) {
  646. int isdef = !strcmp(ssd->savedsession, "Default Settings");
  647. if (!ssd->savedsession[0]) {
  648. int i = dlg_listbox_index(ssd->listbox, dlg);
  649. if (i < 0) {
  650. dlg_beep(dlg);
  651. return;
  652. }
  653. isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings");
  654. sfree(ssd->savedsession);
  655. ssd->savedsession = dupstr(isdef ? "" :
  656. ssd->sesslist.sessions[i]);
  657. }
  658. {
  659. char *errmsg = save_settings(ssd->savedsession, conf);
  660. if (errmsg) {
  661. dlg_error_msg(dlg, errmsg);
  662. sfree(errmsg);
  663. }
  664. }
  665. get_sesslist(&ssd->sesslist, FALSE);
  666. get_sesslist(&ssd->sesslist, TRUE);
  667. dlg_refresh(ssd->editbox, dlg);
  668. dlg_refresh(ssd->listbox, dlg);
  669. } else if (!ssd->midsession &&
  670. ssd->delbutton && ctrl == ssd->delbutton) {
  671. int i = dlg_listbox_index(ssd->listbox, dlg);
  672. if (i <= 0) {
  673. dlg_beep(dlg);
  674. } else {
  675. del_settings(ssd->sesslist.sessions[i]);
  676. get_sesslist(&ssd->sesslist, FALSE);
  677. get_sesslist(&ssd->sesslist, TRUE);
  678. dlg_refresh(ssd->listbox, dlg);
  679. }
  680. } else if (ctrl == ssd->okbutton) {
  681. if (ssd->midsession) {
  682. /* In a mid-session Change Settings, Apply is always OK. */
  683. dlg_end(dlg, 1);
  684. return;
  685. }
  686. /*
  687. * Annoying special case. If the `Open' button is
  688. * pressed while no host name is currently set, _and_
  689. * the session list previously had the focus, _and_
  690. * there was a session selected in that which had a
  691. * valid host name in it, then load it and go.
  692. */
  693. if (dlg_last_focused(ctrl, dlg) == ssd->listbox &&
  694. !conf_launchable(conf)) {
  695. Conf *conf2 = conf_new();
  696. int mbl = FALSE;
  697. if (!load_selected_session(ssd, dlg, conf2, &mbl)) {
  698. dlg_beep(dlg);
  699. conf_free(conf2);
  700. return;
  701. }
  702. /* If at this point we have a valid session, go! */
  703. if (mbl && conf_launchable(conf2)) {
  704. conf_copy_into(conf, conf2);
  705. dlg_end(dlg, 1);
  706. } else
  707. dlg_beep(dlg);
  708. conf_free(conf2);
  709. return;
  710. }
  711. /*
  712. * Otherwise, do the normal thing: if we have a valid
  713. * session, get going.
  714. */
  715. if (conf_launchable(conf)) {
  716. dlg_end(dlg, 1);
  717. } else
  718. dlg_beep(dlg);
  719. } else if (ctrl == ssd->cancelbutton) {
  720. dlg_end(dlg, 0);
  721. }
  722. }
  723. }
  724. struct charclass_data {
  725. union control *listbox, *editbox, *button;
  726. };
  727. static void charclass_handler(union control *ctrl, void *dlg,
  728. void *data, int event)
  729. {
  730. Conf *conf = (Conf *)data;
  731. struct charclass_data *ccd =
  732. (struct charclass_data *)ctrl->generic.context.p;
  733. if (event == EVENT_REFRESH) {
  734. if (ctrl == ccd->listbox) {
  735. int i;
  736. dlg_update_start(ctrl, dlg);
  737. dlg_listbox_clear(ctrl, dlg);
  738. for (i = 0; i < 128; i++) {
  739. char str[100];
  740. sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
  741. (i >= 0x21 && i != 0x7F) ? i : ' ',
  742. conf_get_int_int(conf, CONF_wordness, i));
  743. dlg_listbox_add(ctrl, dlg, str);
  744. }
  745. dlg_update_done(ctrl, dlg);
  746. }
  747. } else if (event == EVENT_ACTION) {
  748. if (ctrl == ccd->button) {
  749. char *str;
  750. int i, n;
  751. str = dlg_editbox_get(ccd->editbox, dlg);
  752. n = atoi(str);
  753. sfree(str);
  754. for (i = 0; i < 128; i++) {
  755. if (dlg_listbox_issel(ccd->listbox, dlg, i))
  756. conf_set_int_int(conf, CONF_wordness, i, n);
  757. }
  758. dlg_refresh(ccd->listbox, dlg);
  759. }
  760. }
  761. }
  762. struct colour_data {
  763. union control *listbox, *redit, *gedit, *bedit, *button;
  764. };
  765. static const char *const colours[] = {
  766. "Default Foreground", "Default Bold Foreground",
  767. "Default Background", "Default Bold Background",
  768. "Cursor Text", "Cursor Colour",
  769. "ANSI Black", "ANSI Black Bold",
  770. "ANSI Red", "ANSI Red Bold",
  771. "ANSI Green", "ANSI Green Bold",
  772. "ANSI Yellow", "ANSI Yellow Bold",
  773. "ANSI Blue", "ANSI Blue Bold",
  774. "ANSI Magenta", "ANSI Magenta Bold",
  775. "ANSI Cyan", "ANSI Cyan Bold",
  776. "ANSI White", "ANSI White Bold"
  777. };
  778. static void colour_handler(union control *ctrl, void *dlg,
  779. void *data, int event)
  780. {
  781. Conf *conf = (Conf *)data;
  782. struct colour_data *cd =
  783. (struct colour_data *)ctrl->generic.context.p;
  784. int update = FALSE, clear = FALSE, r, g, b;
  785. if (event == EVENT_REFRESH) {
  786. if (ctrl == cd->listbox) {
  787. int i;
  788. dlg_update_start(ctrl, dlg);
  789. dlg_listbox_clear(ctrl, dlg);
  790. for (i = 0; i < lenof(colours); i++)
  791. dlg_listbox_add(ctrl, dlg, colours[i]);
  792. dlg_update_done(ctrl, dlg);
  793. clear = TRUE;
  794. update = TRUE;
  795. }
  796. } else if (event == EVENT_SELCHANGE) {
  797. if (ctrl == cd->listbox) {
  798. /* The user has selected a colour. Update the RGB text. */
  799. int i = dlg_listbox_index(ctrl, dlg);
  800. if (i < 0) {
  801. clear = TRUE;
  802. } else {
  803. clear = FALSE;
  804. r = conf_get_int_int(conf, CONF_colours, i*3+0);
  805. g = conf_get_int_int(conf, CONF_colours, i*3+1);
  806. b = conf_get_int_int(conf, CONF_colours, i*3+2);
  807. }
  808. update = TRUE;
  809. }
  810. } else if (event == EVENT_VALCHANGE) {
  811. if (ctrl == cd->redit || ctrl == cd->gedit || ctrl == cd->bedit) {
  812. /* The user has changed the colour using the edit boxes. */
  813. char *str;
  814. int i, cval;
  815. str = dlg_editbox_get(ctrl, dlg);
  816. cval = atoi(str);
  817. sfree(str);
  818. if (cval > 255) cval = 255;
  819. if (cval < 0) cval = 0;
  820. i = dlg_listbox_index(cd->listbox, dlg);
  821. if (i >= 0) {
  822. if (ctrl == cd->redit)
  823. conf_set_int_int(conf, CONF_colours, i*3+0, cval);
  824. else if (ctrl == cd->gedit)
  825. conf_set_int_int(conf, CONF_colours, i*3+1, cval);
  826. else if (ctrl == cd->bedit)
  827. conf_set_int_int(conf, CONF_colours, i*3+2, cval);
  828. }
  829. }
  830. } else if (event == EVENT_ACTION) {
  831. if (ctrl == cd->button) {
  832. int i = dlg_listbox_index(cd->listbox, dlg);
  833. if (i < 0) {
  834. dlg_beep(dlg);
  835. return;
  836. }
  837. /*
  838. * Start a colour selector, which will send us an
  839. * EVENT_CALLBACK when it's finished and allow us to
  840. * pick up the results.
  841. */
  842. dlg_coloursel_start(ctrl, dlg,
  843. conf_get_int_int(conf, CONF_colours, i*3+0),
  844. conf_get_int_int(conf, CONF_colours, i*3+1),
  845. conf_get_int_int(conf, CONF_colours, i*3+2));
  846. }
  847. } else if (event == EVENT_CALLBACK) {
  848. if (ctrl == cd->button) {
  849. int i = dlg_listbox_index(cd->listbox, dlg);
  850. /*
  851. * Collect the results of the colour selector. Will
  852. * return nonzero on success, or zero if the colour
  853. * selector did nothing (user hit Cancel, for example).
  854. */
  855. if (dlg_coloursel_results(ctrl, dlg, &r, &g, &b)) {
  856. conf_set_int_int(conf, CONF_colours, i*3+0, r);
  857. conf_set_int_int(conf, CONF_colours, i*3+1, g);
  858. conf_set_int_int(conf, CONF_colours, i*3+2, b);
  859. clear = FALSE;
  860. update = TRUE;
  861. }
  862. }
  863. }
  864. if (update) {
  865. if (clear) {
  866. dlg_editbox_set(cd->redit, dlg, "");
  867. dlg_editbox_set(cd->gedit, dlg, "");
  868. dlg_editbox_set(cd->bedit, dlg, "");
  869. } else {
  870. char buf[40];
  871. sprintf(buf, "%d", r); dlg_editbox_set(cd->redit, dlg, buf);
  872. sprintf(buf, "%d", g); dlg_editbox_set(cd->gedit, dlg, buf);
  873. sprintf(buf, "%d", b); dlg_editbox_set(cd->bedit, dlg, buf);
  874. }
  875. }
  876. }
  877. struct ttymodes_data {
  878. union control *modelist, *valradio, *valbox;
  879. union control *addbutton, *rembutton, *listbox;
  880. };
  881. static void ttymodes_handler(union control *ctrl, void *dlg,
  882. void *data, int event)
  883. {
  884. Conf *conf = (Conf *)data;
  885. struct ttymodes_data *td =
  886. (struct ttymodes_data *)ctrl->generic.context.p;
  887. if (event == EVENT_REFRESH) {
  888. if (ctrl == td->listbox) {
  889. char *key, *val;
  890. dlg_update_start(ctrl, dlg);
  891. dlg_listbox_clear(ctrl, dlg);
  892. for (val = conf_get_str_strs(conf, CONF_ttymodes, NULL, &key);
  893. val != NULL;
  894. val = conf_get_str_strs(conf, CONF_ttymodes, key, &key)) {
  895. char *disp = dupprintf("%s\t%s", key,
  896. (val[0] == 'A') ? "(auto)" : val+1);
  897. dlg_listbox_add(ctrl, dlg, disp);
  898. sfree(disp);
  899. }
  900. dlg_update_done(ctrl, dlg);
  901. } else if (ctrl == td->modelist) {
  902. int i;
  903. dlg_update_start(ctrl, dlg);
  904. dlg_listbox_clear(ctrl, dlg);
  905. for (i = 0; ttymodes[i]; i++)
  906. dlg_listbox_add(ctrl, dlg, ttymodes[i]);
  907. dlg_listbox_select(ctrl, dlg, 0); /* *shrug* */
  908. dlg_update_done(ctrl, dlg);
  909. } else if (ctrl == td->valradio) {
  910. dlg_radiobutton_set(ctrl, dlg, 0);
  911. }
  912. } else if (event == EVENT_ACTION) {
  913. if (ctrl == td->addbutton) {
  914. int ind = dlg_listbox_index(td->modelist, dlg);
  915. if (ind >= 0) {
  916. char type = dlg_radiobutton_get(td->valradio, dlg) ? 'V' : 'A';
  917. const char *key;
  918. char *str, *val;
  919. /* Construct new entry */
  920. key = ttymodes[ind];
  921. str = dlg_editbox_get(td->valbox, dlg);
  922. val = dupprintf("%c%s", type, str);
  923. sfree(str);
  924. conf_set_str_str(conf, CONF_ttymodes, key, val);
  925. sfree(val);
  926. dlg_refresh(td->listbox, dlg);
  927. } else
  928. dlg_beep(dlg);
  929. } else if (ctrl == td->rembutton) {
  930. int i = 0;
  931. char *key, *val;
  932. int multisel = dlg_listbox_index(td->listbox, dlg) < 0;
  933. for (val = conf_get_str_strs(conf, CONF_ttymodes, NULL, &key);
  934. val != NULL;
  935. val = conf_get_str_strs(conf, CONF_ttymodes, key, &key)) {
  936. if (dlg_listbox_issel(td->listbox, dlg, i)) {
  937. if (!multisel) {
  938. /* Populate controls with entry we're about to
  939. * delete, for ease of editing.
  940. * (If multiple entries were selected, don't
  941. * touch the controls.) */
  942. int ind = 0;
  943. val++;
  944. while (ttymodes[ind]) {
  945. if (!strcmp(ttymodes[ind], key))
  946. break;
  947. ind++;
  948. }
  949. dlg_listbox_select(td->modelist, dlg, ind);
  950. dlg_radiobutton_set(td->valradio, dlg,
  951. (*val == 'V'));
  952. dlg_editbox_set(td->valbox, dlg, val+1);
  953. }
  954. conf_del_str_str(conf, CONF_ttymodes, key);
  955. }
  956. i++;
  957. }
  958. dlg_refresh(td->listbox, dlg);
  959. }
  960. }
  961. }
  962. struct environ_data {
  963. union control *varbox, *valbox, *addbutton, *rembutton, *listbox;
  964. };
  965. static void environ_handler(union control *ctrl, void *dlg,
  966. void *data, int event)
  967. {
  968. Conf *conf = (Conf *)data;
  969. struct environ_data *ed =
  970. (struct environ_data *)ctrl->generic.context.p;
  971. if (event == EVENT_REFRESH) {
  972. if (ctrl == ed->listbox) {
  973. char *key, *val;
  974. dlg_update_start(ctrl, dlg);
  975. dlg_listbox_clear(ctrl, dlg);
  976. for (val = conf_get_str_strs(conf, CONF_environmt, NULL, &key);
  977. val != NULL;
  978. val = conf_get_str_strs(conf, CONF_environmt, key, &key)) {
  979. char *p = dupprintf("%s\t%s", key, val);
  980. dlg_listbox_add(ctrl, dlg, p);
  981. sfree(p);
  982. }
  983. dlg_update_done(ctrl, dlg);
  984. }
  985. } else if (event == EVENT_ACTION) {
  986. if (ctrl == ed->addbutton) {
  987. char *key, *val, *str;
  988. key = dlg_editbox_get(ed->varbox, dlg);
  989. if (!*key) {
  990. sfree(key);
  991. dlg_beep(dlg);
  992. return;
  993. }
  994. val = dlg_editbox_get(ed->valbox, dlg);
  995. if (!*val) {
  996. sfree(key);
  997. sfree(val);
  998. dlg_beep(dlg);
  999. return;
  1000. }
  1001. conf_set_str_str(conf, CONF_environmt, key, val);
  1002. str = dupcat(key, "\t", val, NULL);
  1003. dlg_editbox_set(ed->varbox, dlg, "");
  1004. dlg_editbox_set(ed->valbox, dlg, "");
  1005. sfree(str);
  1006. sfree(key);
  1007. sfree(val);
  1008. dlg_refresh(ed->listbox, dlg);
  1009. } else if (ctrl == ed->rembutton) {
  1010. int i = dlg_listbox_index(ed->listbox, dlg);
  1011. if (i < 0) {
  1012. dlg_beep(dlg);
  1013. } else {
  1014. char *key, *val;
  1015. key = conf_get_str_nthstrkey(conf, CONF_environmt, i);
  1016. if (key) {
  1017. /* Populate controls with the entry we're about to delete
  1018. * for ease of editing */
  1019. val = conf_get_str_str(conf, CONF_environmt, key);
  1020. dlg_editbox_set(ed->varbox, dlg, key);
  1021. dlg_editbox_set(ed->valbox, dlg, val);
  1022. /* And delete it */
  1023. conf_del_str_str(conf, CONF_environmt, key);
  1024. }
  1025. }
  1026. dlg_refresh(ed->listbox, dlg);
  1027. }
  1028. }
  1029. }
  1030. struct portfwd_data {
  1031. union control *addbutton, *rembutton, *listbox;
  1032. union control *sourcebox, *destbox, *direction;
  1033. #ifndef NO_IPV6
  1034. union control *addressfamily;
  1035. #endif
  1036. };
  1037. static void portfwd_handler(union control *ctrl, void *dlg,
  1038. void *data, int event)
  1039. {
  1040. Conf *conf = (Conf *)data;
  1041. struct portfwd_data *pfd =
  1042. (struct portfwd_data *)ctrl->generic.context.p;
  1043. if (event == EVENT_REFRESH) {
  1044. if (ctrl == pfd->listbox) {
  1045. char *key, *val;
  1046. dlg_update_start(ctrl, dlg);
  1047. dlg_listbox_clear(ctrl, dlg);
  1048. for (val = conf_get_str_strs(conf, CONF_portfwd, NULL, &key);
  1049. val != NULL;
  1050. val = conf_get_str_strs(conf, CONF_portfwd, key, &key)) {
  1051. char *p;
  1052. if (!strcmp(val, "D")) {
  1053. char *L;
  1054. /*
  1055. * A dynamic forwarding is stored as L12345=D or
  1056. * 6L12345=D (since it's mutually exclusive with
  1057. * L12345=anything else), but displayed as D12345
  1058. * to match the fiction that 'Local', 'Remote' and
  1059. * 'Dynamic' are three distinct modes and also to
  1060. * align with OpenSSH's command line option syntax
  1061. * that people will already be used to. So, for
  1062. * display purposes, find the L in the key string
  1063. * and turn it into a D.
  1064. */
  1065. p = dupprintf("%s\t", key);
  1066. L = strchr(p, 'L');
  1067. if (L) *L = 'D';
  1068. } else
  1069. p = dupprintf("%s\t%s", key, val);
  1070. dlg_listbox_add(ctrl, dlg, p);
  1071. sfree(p);
  1072. }
  1073. dlg_update_done(ctrl, dlg);
  1074. } else if (ctrl == pfd->direction) {
  1075. /*
  1076. * Default is Local.
  1077. */
  1078. dlg_radiobutton_set(ctrl, dlg, 0);
  1079. #ifndef NO_IPV6
  1080. } else if (ctrl == pfd->addressfamily) {
  1081. dlg_radiobutton_set(ctrl, dlg, 0);
  1082. #endif
  1083. }
  1084. } else if (event == EVENT_ACTION) {
  1085. if (ctrl == pfd->addbutton) {
  1086. const char *family, *type;
  1087. char *src, *key, *val;
  1088. int whichbutton;
  1089. #ifndef NO_IPV6
  1090. whichbutton = dlg_radiobutton_get(pfd->addressfamily, dlg);
  1091. if (whichbutton == 1)
  1092. family = "4";
  1093. else if (whichbutton == 2)
  1094. family = "6";
  1095. else
  1096. #endif
  1097. family = "";
  1098. whichbutton = dlg_radiobutton_get(pfd->direction, dlg);
  1099. if (whichbutton == 0)
  1100. type = "L";
  1101. else if (whichbutton == 1)
  1102. type = "R";
  1103. else
  1104. type = "D";
  1105. src = dlg_editbox_get(pfd->sourcebox, dlg);
  1106. if (!*src) {
  1107. dlg_error_msg(dlg, "You need to specify a source port number");
  1108. sfree(src);
  1109. return;
  1110. }
  1111. if (*type != 'D') {
  1112. val = dlg_editbox_get(pfd->destbox, dlg);
  1113. if (!*val || !host_strchr(val, ':')) {
  1114. dlg_error_msg(dlg,
  1115. "You need to specify a destination address\n"
  1116. "in the form \"host.name:port\"");
  1117. sfree(src);
  1118. sfree(val);
  1119. return;
  1120. }
  1121. } else {
  1122. type = "L";
  1123. val = dupstr("D"); /* special case */
  1124. }
  1125. key = dupcat(family, type, src, NULL);
  1126. sfree(src);
  1127. if (conf_get_str_str_opt(conf, CONF_portfwd, key)) {
  1128. dlg_error_msg(dlg, "Specified forwarding already exists");
  1129. } else {
  1130. conf_set_str_str(conf, CONF_portfwd, key, val);
  1131. }
  1132. sfree(key);
  1133. sfree(val);
  1134. dlg_refresh(pfd->listbox, dlg);
  1135. } else if (ctrl == pfd->rembutton) {
  1136. int i = dlg_listbox_index(pfd->listbox, dlg);
  1137. if (i < 0) {
  1138. dlg_beep(dlg);
  1139. } else {
  1140. char *key, *p;
  1141. const char *val;
  1142. key = conf_get_str_nthstrkey(conf, CONF_portfwd, i);
  1143. if (key) {
  1144. static const char *const afs = "A46";
  1145. static const char *const dirs = "LRD";
  1146. char *afp;
  1147. int dir;
  1148. #ifndef NO_IPV6
  1149. int idx;
  1150. #endif
  1151. /* Populate controls with the entry we're about to delete
  1152. * for ease of editing */
  1153. p = key;
  1154. afp = strchr(afs, *p);
  1155. #ifndef NO_IPV6
  1156. idx = afp ? afp-afs : 0;
  1157. #endif
  1158. if (afp)
  1159. p++;
  1160. #ifndef NO_IPV6
  1161. dlg_radiobutton_set(pfd->addressfamily, dlg, idx);
  1162. #endif
  1163. dir = *p;
  1164. val = conf_get_str_str(conf, CONF_portfwd, key);
  1165. if (!strcmp(val, "D")) {
  1166. dir = 'D';
  1167. val = "";
  1168. }
  1169. dlg_radiobutton_set(pfd->direction, dlg,
  1170. strchr(dirs, dir) - dirs);
  1171. p++;
  1172. dlg_editbox_set(pfd->sourcebox, dlg, p);
  1173. dlg_editbox_set(pfd->destbox, dlg, val);
  1174. /* And delete it */
  1175. conf_del_str_str(conf, CONF_portfwd, key);
  1176. }
  1177. }
  1178. dlg_refresh(pfd->listbox, dlg);
  1179. }
  1180. }
  1181. }
  1182. struct manual_hostkey_data {
  1183. union control *addbutton, *rembutton, *listbox, *keybox;
  1184. };
  1185. static void manual_hostkey_handler(union control *ctrl, void *dlg,
  1186. void *data, int event)
  1187. {
  1188. Conf *conf = (Conf *)data;
  1189. struct manual_hostkey_data *mh =
  1190. (struct manual_hostkey_data *)ctrl->generic.context.p;
  1191. if (event == EVENT_REFRESH) {
  1192. if (ctrl == mh->listbox) {
  1193. char *key, *val;
  1194. dlg_update_start(ctrl, dlg);
  1195. dlg_listbox_clear(ctrl, dlg);
  1196. for (val = conf_get_str_strs(conf, CONF_ssh_manual_hostkeys,
  1197. NULL, &key);
  1198. val != NULL;
  1199. val = conf_get_str_strs(conf, CONF_ssh_manual_hostkeys,
  1200. key, &key)) {
  1201. dlg_listbox_add(ctrl, dlg, key);
  1202. }
  1203. dlg_update_done(ctrl, dlg);
  1204. }
  1205. } else if (event == EVENT_ACTION) {
  1206. if (ctrl == mh->addbutton) {
  1207. char *key;
  1208. key = dlg_editbox_get(mh->keybox, dlg);
  1209. if (!*key) {
  1210. dlg_error_msg(dlg, "You need to specify a host key or "
  1211. "fingerprint");
  1212. sfree(key);
  1213. return;
  1214. }
  1215. if (!validate_manual_hostkey(key)) {
  1216. dlg_error_msg(dlg, "Host key is not in a valid format");
  1217. } else if (conf_get_str_str_opt(conf, CONF_ssh_manual_hostkeys,
  1218. key)) {
  1219. dlg_error_msg(dlg, "Specified host key is already listed");
  1220. } else {
  1221. conf_set_str_str(conf, CONF_ssh_manual_hostkeys, key, "");
  1222. }
  1223. sfree(key);
  1224. dlg_refresh(mh->listbox, dlg);
  1225. } else if (ctrl == mh->rembutton) {
  1226. int i = dlg_listbox_index(mh->listbox, dlg);
  1227. if (i < 0) {
  1228. dlg_beep(dlg);
  1229. } else {
  1230. char *key;
  1231. key = conf_get_str_nthstrkey(conf, CONF_ssh_manual_hostkeys, i);
  1232. if (key) {
  1233. dlg_editbox_set(mh->keybox, dlg, key);
  1234. /* And delete it */
  1235. conf_del_str_str(conf, CONF_ssh_manual_hostkeys, key);
  1236. }
  1237. }
  1238. dlg_refresh(mh->listbox, dlg);
  1239. }
  1240. }
  1241. }
  1242. void setup_config_box(struct controlbox *b, int midsession,
  1243. int protocol, int protcfginfo)
  1244. {
  1245. struct controlset *s;
  1246. struct sessionsaver_data *ssd;
  1247. struct charclass_data *ccd;
  1248. struct colour_data *cd;
  1249. struct ttymodes_data *td;
  1250. struct environ_data *ed;
  1251. struct portfwd_data *pfd;
  1252. struct manual_hostkey_data *mh;
  1253. union control *c;
  1254. char *str;
  1255. ssd = (struct sessionsaver_data *)
  1256. ctrl_alloc_with_free(b, sizeof(struct sessionsaver_data),
  1257. sessionsaver_data_free);
  1258. memset(ssd, 0, sizeof(*ssd));
  1259. ssd->savedsession = dupstr("");
  1260. ssd->midsession = midsession;
  1261. /*
  1262. * The standard panel that appears at the bottom of all panels:
  1263. * Open, Cancel, Apply etc.
  1264. */
  1265. s = ctrl_getset(b, "", "", "");
  1266. ctrl_columns(s, 5, 20, 20, 20, 20, 20);
  1267. ssd->okbutton = ctrl_pushbutton(s,
  1268. (midsession ? "Apply" : "Open"),
  1269. (char)(midsession ? 'a' : 'o'),
  1270. HELPCTX(no_help),
  1271. sessionsaver_handler, P(ssd));
  1272. ssd->okbutton->button.isdefault = TRUE;
  1273. ssd->okbutton->generic.column = 3;
  1274. ssd->cancelbutton = ctrl_pushbutton(s, "Cancel", 'c', HELPCTX(no_help),
  1275. sessionsaver_handler, P(ssd));
  1276. ssd->cancelbutton->button.iscancel = TRUE;
  1277. ssd->cancelbutton->generic.column = 4;
  1278. /* We carefully don't close the 5-column part, so that platform-
  1279. * specific add-ons can put extra buttons alongside Open and Cancel. */
  1280. /*
  1281. * The Session panel.
  1282. */
  1283. str = dupprintf("Basic options for your %s session", appname);
  1284. ctrl_settitle(b, "Session", str);
  1285. sfree(str);
  1286. if (!midsession) {
  1287. struct hostport *hp = (struct hostport *)
  1288. ctrl_alloc(b, sizeof(struct hostport));
  1289. s = ctrl_getset(b, "Session", "hostport",
  1290. "Specify the destination you want to connect to");
  1291. ctrl_columns(s, 2, 75, 25);
  1292. c = ctrl_editbox(s, HOST_BOX_TITLE, 'n', 100,
  1293. HELPCTX(session_hostname),
  1294. config_host_handler, I(0), I(0));
  1295. c->generic.column = 0;
  1296. hp->host = c;
  1297. c = ctrl_editbox(s, PORT_BOX_TITLE, 'p', 100,
  1298. HELPCTX(session_hostname),
  1299. config_port_handler, I(0), I(0));
  1300. c->generic.column = 1;
  1301. hp->port = c;
  1302. ctrl_columns(s, 1, 100);
  1303. if (!backend_from_proto(PROT_SSH)) {
  1304. ctrl_radiobuttons(s, "Connection type:", NO_SHORTCUT, 3,
  1305. HELPCTX(session_hostname),
  1306. config_protocolbuttons_handler, P(hp),
  1307. "Raw", 'w', I(PROT_RAW),
  1308. "Telnet", 't', I(PROT_TELNET),
  1309. "Rlogin", 'i', I(PROT_RLOGIN),
  1310. NULL);
  1311. } else {
  1312. ctrl_radiobuttons(s, "Connection type:", NO_SHORTCUT, 4,
  1313. HELPCTX(session_hostname),
  1314. config_protocolbuttons_handler, P(hp),
  1315. "Raw", 'w', I(PROT_RAW),
  1316. "Telnet", 't', I(PROT_TELNET),
  1317. "Rlogin", 'i', I(PROT_RLOGIN),
  1318. "SSH", 's', I(PROT_SSH),
  1319. NULL);
  1320. }
  1321. }
  1322. /*
  1323. * The Load/Save panel is available even in mid-session.
  1324. */
  1325. s = ctrl_getset(b, "Session", "savedsessions",
  1326. midsession ? "Save the current session settings" :
  1327. "Load, save or delete a stored session");
  1328. ctrl_columns(s, 2, 75, 25);
  1329. get_sesslist(&ssd->sesslist, TRUE);
  1330. ssd->editbox = ctrl_editbox(s, "Saved Sessions", 'e', 100,
  1331. HELPCTX(session_saved),
  1332. sessionsaver_handler, P(ssd), P(NULL));
  1333. ssd->editbox->generic.column = 0;
  1334. /* Reset columns so that the buttons are alongside the list, rather
  1335. * than alongside that edit box. */
  1336. ctrl_columns(s, 1, 100);
  1337. ctrl_columns(s, 2, 75, 25);
  1338. ssd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
  1339. HELPCTX(session_saved),
  1340. sessionsaver_handler, P(ssd));
  1341. ssd->listbox->generic.column = 0;
  1342. ssd->listbox->listbox.height = 7;
  1343. if (!midsession) {
  1344. ssd->loadbutton = ctrl_pushbutton(s, "Load", 'l',
  1345. HELPCTX(session_saved),
  1346. sessionsaver_handler, P(ssd));
  1347. ssd->loadbutton->generic.column = 1;
  1348. } else {
  1349. /* We can't offer the Load button mid-session, as it would allow the
  1350. * user to load and subsequently save settings they can't see. (And
  1351. * also change otherwise immutable settings underfoot; that probably
  1352. * shouldn't be a problem, but.) */
  1353. ssd->loadbutton = NULL;
  1354. }
  1355. /* "Save" button is permitted mid-session. */
  1356. ssd->savebutton = ctrl_pushbutton(s, "Save", 'v',
  1357. HELPCTX(session_saved),
  1358. sessionsaver_handler, P(ssd));
  1359. ssd->savebutton->generic.column = 1;
  1360. if (!midsession) {
  1361. ssd->delbutton = ctrl_pushbutton(s, "Delete", 'd',
  1362. HELPCTX(session_saved),
  1363. sessionsaver_handler, P(ssd));
  1364. ssd->delbutton->generic.column = 1;
  1365. } else {
  1366. /* Disable the Delete button mid-session too, for UI consistency. */
  1367. ssd->delbutton = NULL;
  1368. }
  1369. ctrl_columns(s, 1, 100);
  1370. s = ctrl_getset(b, "Session", "otheropts", NULL);
  1371. ctrl_radiobuttons(s, "Close window on exit:", 'x', 4,
  1372. HELPCTX(session_coe),
  1373. conf_radiobutton_handler,
  1374. I(CONF_close_on_exit),
  1375. "Always", I(FORCE_ON),
  1376. "Never", I(FORCE_OFF),
  1377. "Only on clean exit", I(AUTO), NULL);
  1378. /*
  1379. * The Session/Logging panel.
  1380. */
  1381. ctrl_settitle(b, "Session/Logging", "Options controlling session logging");
  1382. s = ctrl_getset(b, "Session/Logging", "main", NULL);
  1383. /*
  1384. * The logging buttons change depending on whether SSH packet
  1385. * logging can sensibly be available.
  1386. */
  1387. {
  1388. const char *sshlogname, *sshrawlogname;
  1389. if ((midsession && protocol == PROT_SSH) ||
  1390. (!midsession && backend_from_proto(PROT_SSH))) {
  1391. sshlogname = "SSH packets";
  1392. sshrawlogname = "SSH packets and raw data";
  1393. } else {
  1394. sshlogname = NULL; /* this will disable both buttons */
  1395. sshrawlogname = NULL; /* this will just placate optimisers */
  1396. }
  1397. ctrl_radiobuttons(s, "Session logging:", NO_SHORTCUT, 2,
  1398. HELPCTX(logging_main),
  1399. loggingbuttons_handler,
  1400. I(CONF_logtype),
  1401. "None", 't', I(LGTYP_NONE),
  1402. "Printable output", 'p', I(LGTYP_ASCII),
  1403. "All session output", 'l', I(LGTYP_DEBUG),
  1404. sshlogname, 's', I(LGTYP_PACKETS),
  1405. sshrawlogname, 'r', I(LGTYP_SSHRAW),
  1406. NULL);
  1407. }
  1408. ctrl_filesel(s, "Log file name:", 'f',
  1409. NULL, TRUE, "Select session log file name",
  1410. HELPCTX(logging_filename),
  1411. conf_filesel_handler, I(CONF_logfilename));
  1412. ctrl_text(s, "(Log file name can contain &Y, &M, &D for date,"
  1413. " &T for time, &H for host name, and &P for port number)",
  1414. HELPCTX(logging_filename));
  1415. ctrl_radiobuttons(s, "What to do if the log file already exists:", 'e', 1,
  1416. HELPCTX(logging_exists),
  1417. conf_radiobutton_handler, I(CONF_logxfovr),
  1418. "Always overwrite it", I(LGXF_OVR),
  1419. "Always append to the end of it", I(LGXF_APN),
  1420. "Ask the user every time", I(LGXF_ASK), NULL);
  1421. ctrl_checkbox(s, "Flush log file frequently", 'u',
  1422. HELPCTX(logging_flush),
  1423. conf_checkbox_handler, I(CONF_logflush));
  1424. if ((midsession && protocol == PROT_SSH) ||
  1425. (!midsession && backend_from_proto(PROT_SSH))) {
  1426. s = ctrl_getset(b, "Session/Logging", "ssh",
  1427. "Options specific to SSH packet logging");
  1428. ctrl_checkbox(s, "Omit known password fields", 'k',
  1429. HELPCTX(logging_ssh_omit_password),
  1430. conf_checkbox_handler, I(CONF_logomitpass));
  1431. ctrl_checkbox(s, "Omit session data", 'd',
  1432. HELPCTX(logging_ssh_omit_data),
  1433. conf_checkbox_handler, I(CONF_logomitdata));
  1434. }
  1435. /*
  1436. * The Terminal panel.
  1437. */
  1438. ctrl_settitle(b, "Terminal", "Options controlling the terminal emulation");
  1439. s = ctrl_getset(b, "Terminal", "general", "Set various terminal options");
  1440. ctrl_checkbox(s, "Auto wrap mode initially on", 'w',
  1441. HELPCTX(terminal_autowrap),
  1442. conf_checkbox_handler, I(CONF_wrap_mode));
  1443. ctrl_checkbox(s, "DEC Origin Mode initially on", 'd',
  1444. HELPCTX(terminal_decom),
  1445. conf_checkbox_handler, I(CONF_dec_om));
  1446. ctrl_checkbox(s, "Implicit CR in every LF", 'r',
  1447. HELPCTX(terminal_lfhascr),
  1448. conf_checkbox_handler, I(CONF_lfhascr));
  1449. ctrl_checkbox(s, "Implicit LF in every CR", 'f',
  1450. HELPCTX(terminal_crhaslf),
  1451. conf_checkbox_handler, I(CONF_crhaslf));
  1452. ctrl_checkbox(s, "Use background colour to erase screen", 'e',
  1453. HELPCTX(terminal_bce),
  1454. conf_checkbox_handler, I(CONF_bce));
  1455. ctrl_checkbox(s, "Enable blinking text", 'n',
  1456. HELPCTX(terminal_blink),
  1457. conf_checkbox_handler, I(CONF_blinktext));
  1458. ctrl_editbox(s, "Answerback to ^E:", 's', 100,
  1459. HELPCTX(terminal_answerback),
  1460. conf_editbox_handler, I(CONF_answerback), I(1));
  1461. s = ctrl_getset(b, "Terminal", "ldisc", "Line discipline options");
  1462. ctrl_radiobuttons(s, "Local echo:", 'l', 3,
  1463. HELPCTX(terminal_localecho),
  1464. conf_radiobutton_handler,I(CONF_localecho),
  1465. "Auto", I(AUTO),
  1466. "Force on", I(FORCE_ON),
  1467. "Force off", I(FORCE_OFF), NULL);
  1468. ctrl_radiobuttons(s, "Local line editing:", 't', 3,
  1469. HELPCTX(terminal_localedit),
  1470. conf_radiobutton_handler,I(CONF_localedit),
  1471. "Auto", I(AUTO),
  1472. "Force on", I(FORCE_ON),
  1473. "Force off", I(FORCE_OFF), NULL);
  1474. s = ctrl_getset(b, "Terminal", "printing", "Remote-controlled printing");
  1475. ctrl_combobox(s, "Printer to send ANSI printer output to:", 'p', 100,
  1476. HELPCTX(terminal_printing),
  1477. printerbox_handler, P(NULL), P(NULL));
  1478. /*
  1479. * The Terminal/Keyboard panel.
  1480. */
  1481. ctrl_settitle(b, "Terminal/Keyboard",
  1482. "Options controlling the effects of keys");
  1483. s = ctrl_getset(b, "Terminal/Keyboard", "mappings",
  1484. "Change the sequences sent by:");
  1485. ctrl_radiobuttons(s, "The Backspace key", 'b', 2,
  1486. HELPCTX(keyboard_backspace),
  1487. conf_radiobutton_handler,
  1488. I(CONF_bksp_is_delete),
  1489. "Control-H", I(0), "Control-? (127)", I(1), NULL);
  1490. ctrl_radiobuttons(s, "The Home and End keys", 'e', 2,
  1491. HELPCTX(keyboard_homeend),
  1492. conf_radiobutton_handler,
  1493. I(CONF_rxvt_homeend),
  1494. "Standard", I(0), "rxvt", I(1), NULL);
  1495. ctrl_radiobuttons(s, "The Function keys and keypad", 'f', 3,
  1496. HELPCTX(keyboard_funkeys),
  1497. conf_radiobutton_handler,
  1498. I(CONF_funky_type),
  1499. "ESC[n~", I(0), "Linux", I(1), "Xterm R6", I(2),
  1500. "VT400", I(3), "VT100+", I(4), "SCO", I(5), NULL);
  1501. s = ctrl_getset(b, "Terminal/Keyboard", "appkeypad",
  1502. "Application keypad settings:");
  1503. ctrl_radiobuttons(s, "Initial state of cursor keys:", 'r', 3,
  1504. HELPCTX(keyboard_appcursor),
  1505. conf_radiobutton_handler,
  1506. I(CONF_app_cursor),
  1507. "Normal", I(0), "Application", I(1), NULL);
  1508. ctrl_radiobuttons(s, "Initial state of numeric keypad:", 'n', 3,
  1509. HELPCTX(keyboard_appkeypad),
  1510. numeric_keypad_handler, P(NULL),
  1511. "Normal", I(0), "Application", I(1), "NetHack", I(2),
  1512. NULL);
  1513. /*
  1514. * The Terminal/Bell panel.
  1515. */
  1516. ctrl_settitle(b, "Terminal/Bell",
  1517. "Options controlling the terminal bell");
  1518. s = ctrl_getset(b, "Terminal/Bell", "style", "Set the style of bell");
  1519. ctrl_radiobuttons(s, "Action to happen when a bell occurs:", 'b', 1,
  1520. HELPCTX(bell_style),
  1521. conf_radiobutton_handler, I(CONF_beep),
  1522. "None (bell disabled)", I(BELL_DISABLED),
  1523. "Make default system alert sound", I(BELL_DEFAULT),
  1524. "Visual bell (flash window)", I(BELL_VISUAL), NULL);
  1525. s = ctrl_getset(b, "Terminal/Bell", "overload",
  1526. "Control the bell overload behaviour");
  1527. ctrl_checkbox(s, "Bell is temporarily disabled when over-used", 'd',
  1528. HELPCTX(bell_overload),
  1529. conf_checkbox_handler, I(CONF_bellovl));
  1530. ctrl_editbox(s, "Over-use means this many bells...", 'm', 20,
  1531. HELPCTX(bell_overload),
  1532. conf_editbox_handler, I(CONF_bellovl_n), I(-1));
  1533. ctrl_editbox(s, "... in this many seconds", 't', 20,
  1534. HELPCTX(bell_overload),
  1535. conf_editbox_handler, I(CONF_bellovl_t),
  1536. I(-TICKSPERSEC));
  1537. ctrl_text(s, "The bell is re-enabled after a few seconds of silence.",
  1538. HELPCTX(bell_overload));
  1539. ctrl_editbox(s, "Seconds of silence required", 's', 20,
  1540. HELPCTX(bell_overload),
  1541. conf_editbox_handler, I(CONF_bellovl_s),
  1542. I(-TICKSPERSEC));
  1543. /*
  1544. * The Terminal/Features panel.
  1545. */
  1546. ctrl_settitle(b, "Terminal/Features",
  1547. "Enabling and disabling advanced terminal features");
  1548. s = ctrl_getset(b, "Terminal/Features", "main", NULL);
  1549. ctrl_checkbox(s, "Disable application cursor keys mode", 'u',
  1550. HELPCTX(features_application),
  1551. conf_checkbox_handler, I(CONF_no_applic_c));
  1552. ctrl_checkbox(s, "Disable application keypad mode", 'k',
  1553. HELPCTX(features_application),
  1554. conf_checkbox_handler, I(CONF_no_applic_k));
  1555. ctrl_checkbox(s, "Disable xterm-style mouse reporting", 'x',
  1556. HELPCTX(features_mouse),
  1557. conf_checkbox_handler, I(CONF_no_mouse_rep));
  1558. ctrl_checkbox(s, "Disable remote-controlled terminal resizing", 's',
  1559. HELPCTX(features_resize),
  1560. conf_checkbox_handler,
  1561. I(CONF_no_remote_resize));
  1562. ctrl_checkbox(s, "Disable switching to alternate terminal screen", 'w',
  1563. HELPCTX(features_altscreen),
  1564. conf_checkbox_handler, I(CONF_no_alt_screen));
  1565. ctrl_checkbox(s, "Disable remote-controlled window title changing", 't',
  1566. HELPCTX(features_retitle),
  1567. conf_checkbox_handler,
  1568. I(CONF_no_remote_wintitle));
  1569. ctrl_radiobuttons(s, "Response to remote title query (SECURITY):", 'q', 3,
  1570. HELPCTX(features_qtitle),
  1571. conf_radiobutton_handler,
  1572. I(CONF_remote_qtitle_action),
  1573. "None", I(TITLE_NONE),
  1574. "Empty string", I(TITLE_EMPTY),
  1575. "Window title", I(TITLE_REAL), NULL);
  1576. ctrl_checkbox(s, "Disable destructive backspace on server sending ^?",'b',
  1577. HELPCTX(features_dbackspace),
  1578. conf_checkbox_handler, I(CONF_no_dbackspace));
  1579. ctrl_checkbox(s, "Disable remote-controlled character set configuration",
  1580. 'r', HELPCTX(features_charset), conf_checkbox_handler,
  1581. I(CONF_no_remote_charset));
  1582. ctrl_checkbox(s, "Disable Arabic text shaping",
  1583. 'l', HELPCTX(features_arabicshaping), conf_checkbox_handler,
  1584. I(CONF_arabicshaping));
  1585. ctrl_checkbox(s, "Disable bidirectional text display",
  1586. 'd', HELPCTX(features_bidi), conf_checkbox_handler,
  1587. I(CONF_bidi));
  1588. /*
  1589. * The Window panel.
  1590. */
  1591. str = dupprintf("Options controlling %s's window", appname);
  1592. ctrl_settitle(b, "Window", str);
  1593. sfree(str);
  1594. s = ctrl_getset(b, "Window", "size", "Set the size of the window");
  1595. ctrl_columns(s, 2, 50, 50);
  1596. c = ctrl_editbox(s, "Columns", 'm', 100,
  1597. HELPCTX(window_size),
  1598. conf_editbox_handler, I(CONF_width), I(-1));
  1599. c->generic.column = 0;
  1600. c = ctrl_editbox(s, "Rows", 'r', 100,
  1601. HELPCTX(window_size),
  1602. conf_editbox_handler, I(CONF_height),I(-1));
  1603. c->generic.column = 1;
  1604. ctrl_columns(s, 1, 100);
  1605. s = ctrl_getset(b, "Window", "scrollback",
  1606. "Control the scrollback in the window");
  1607. ctrl_editbox(s, "Lines of scrollback", 's', 50,
  1608. HELPCTX(window_scrollback),
  1609. conf_editbox_handler, I(CONF_savelines), I(-1));
  1610. ctrl_checkbox(s, "Display scrollbar", 'd',
  1611. HELPCTX(window_scrollback),
  1612. conf_checkbox_handler, I(CONF_scrollbar));
  1613. ctrl_checkbox(s, "Reset scrollback on keypress", 'k',
  1614. HELPCTX(window_scrollback),
  1615. conf_checkbox_handler, I(CONF_scroll_on_key));
  1616. ctrl_checkbox(s, "Reset scrollback on display activity", 'p',
  1617. HELPCTX(window_scrollback),
  1618. conf_checkbox_handler, I(CONF_scroll_on_disp));
  1619. ctrl_checkbox(s, "Push erased text into scrollback", 'e',
  1620. HELPCTX(window_erased),
  1621. conf_checkbox_handler,
  1622. I(CONF_erase_to_scrollback));
  1623. /*
  1624. * The Window/Appearance panel.
  1625. */
  1626. str = dupprintf("Configure the appearance of %s's window", appname);
  1627. ctrl_settitle(b, "Window/Appearance", str);
  1628. sfree(str);
  1629. s = ctrl_getset(b, "Window/Appearance", "cursor",
  1630. "Adjust the use of the cursor");
  1631. ctrl_radiobuttons(s, "Cursor appearance:", NO_SHORTCUT, 3,
  1632. HELPCTX(appearance_cursor),
  1633. conf_radiobutton_handler,
  1634. I(CONF_cursor_type),
  1635. "Block", 'l', I(0),
  1636. "Underline", 'u', I(1),
  1637. "Vertical line", 'v', I(2), NULL);
  1638. ctrl_checkbox(s, "Cursor blinks", 'b',
  1639. HELPCTX(appearance_cursor),
  1640. conf_checkbox_handler, I(CONF_blink_cur));
  1641. s = ctrl_getset(b, "Window/Appearance", "font",
  1642. "Font settings");
  1643. ctrl_fontsel(s, "Font used in the terminal window", 'n',
  1644. HELPCTX(appearance_font),
  1645. conf_fontsel_handler, I(CONF_font));
  1646. s = ctrl_getset(b, "Window/Appearance", "mouse",
  1647. "Adjust the use of the mouse pointer");
  1648. ctrl_checkbox(s, "Hide mouse pointer when typing in window", 'p',
  1649. HELPCTX(appearance_hidemouse),
  1650. conf_checkbox_handler, I(CONF_hide_mouseptr));
  1651. s = ctrl_getset(b, "Window/Appearance", "border",
  1652. "Adjust the window border");
  1653. ctrl_editbox(s, "Gap between text and window edge:", 'e', 20,
  1654. HELPCTX(appearance_border),
  1655. conf_editbox_handler,
  1656. I(CONF_window_border), I(-1));
  1657. /*
  1658. * The Window/Behaviour panel.
  1659. */
  1660. str = dupprintf("Configure the behaviour of %s's window", appname);
  1661. ctrl_settitle(b, "Window/Behaviour", str);
  1662. sfree(str);
  1663. s = ctrl_getset(b, "Window/Behaviour", "title",
  1664. "Adjust the behaviour of the window title");
  1665. ctrl_editbox(s, "Window title:", 't', 100,
  1666. HELPCTX(appearance_title),
  1667. conf_editbox_handler, I(CONF_wintitle), I(1));
  1668. ctrl_checkbox(s, "Separate window and icon titles", 'i',
  1669. HELPCTX(appearance_title),
  1670. conf_checkbox_handler,
  1671. I(CHECKBOX_INVERT | CONF_win_name_always));
  1672. s = ctrl_getset(b, "Window/Behaviour", "main", NULL);
  1673. ctrl_checkbox(s, "Warn before closing window", 'w',
  1674. HELPCTX(behaviour_closewarn),
  1675. conf_checkbox_handler, I(CONF_warn_on_close));
  1676. /*
  1677. * The Window/Translation panel.
  1678. */
  1679. ctrl_settitle(b, "Window/Translation",
  1680. "Options controlling character set translation");
  1681. s = ctrl_getset(b, "Window/Translation", "trans",
  1682. "Character set translation");
  1683. ctrl_combobox(s, "Remote character set:",
  1684. 'r', 100, HELPCTX(translation_codepage),
  1685. codepage_handler, P(NULL), P(NULL));
  1686. s = ctrl_getset(b, "Window/Translation", "tweaks", NULL);
  1687. ctrl_checkbox(s, "Treat CJK ambiguous characters as wide", 'w',
  1688. HELPCTX(translation_cjk_ambig_wide),
  1689. conf_checkbox_handler, I(CONF_cjk_ambig_wide));
  1690. str = dupprintf("Adjust how %s handles line drawing characters", appname);
  1691. s = ctrl_getset(b, "Window/Translation", "linedraw", str);
  1692. sfree(str);
  1693. ctrl_radiobuttons(s, "Handling of line drawing characters:", NO_SHORTCUT,1,
  1694. HELPCTX(translation_linedraw),
  1695. conf_radiobutton_handler,
  1696. I(CONF_vtmode),
  1697. "Use Unicode line drawing code points",'u',I(VT_UNICODE),
  1698. "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN),
  1699. NULL);
  1700. ctrl_checkbox(s, "Copy and paste line drawing characters as lqqqk",'d',
  1701. HELPCTX(selection_linedraw),
  1702. conf_checkbox_handler, I(CONF_rawcnp));
  1703. /*
  1704. * The Window/Selection panel.
  1705. */
  1706. ctrl_settitle(b, "Window/Selection", "Options controlling copy and paste");
  1707. s = ctrl_getset(b, "Window/Selection", "mouse",
  1708. "Control use of mouse");
  1709. ctrl_checkbox(s, "Shift overrides application's use of mouse", 'p',
  1710. HELPCTX(selection_shiftdrag),
  1711. conf_checkbox_handler, I(CONF_mouse_override));
  1712. ctrl_radiobuttons(s,
  1713. "Default selection mode (Alt+drag does the other one):",
  1714. NO_SHORTCUT, 2,
  1715. HELPCTX(selection_rect),
  1716. conf_radiobutton_handler,
  1717. I(CONF_rect_select),
  1718. "Normal", 'n', I(0),
  1719. "Rectangular block", 'r', I(1), NULL);
  1720. s = ctrl_getset(b, "Window/Selection", "charclass",
  1721. "Control the select-one-word-at-a-time mode");
  1722. ccd = (struct charclass_data *)
  1723. ctrl_alloc(b, sizeof(struct charclass_data));
  1724. ccd->listbox = ctrl_listbox(s, "Character classes:", 'e',
  1725. HELPCTX(selection_charclasses),
  1726. charclass_handler, P(ccd));
  1727. ccd->listbox->listbox.multisel = 1;
  1728. ccd->listbox->listbox.ncols = 4;
  1729. ccd->listbox->listbox.percentages = snewn(4, int);
  1730. ccd->listbox->listbox.percentages[0] = 15;
  1731. ccd->listbox->listbox.percentages[1] = 25;
  1732. ccd->listbox->listbox.percentages[2] = 20;
  1733. ccd->listbox->listbox.percentages[3] = 40;
  1734. ctrl_columns(s, 2, 67, 33);
  1735. ccd->editbox = ctrl_editbox(s, "Set to class", 't', 50,
  1736. HELPCTX(selection_charclasses),
  1737. charclass_handler, P(ccd), P(NULL));
  1738. ccd->editbox->generic.column = 0;
  1739. ccd->button = ctrl_pushbutton(s, "Set", 's',
  1740. HELPCTX(selection_charclasses),
  1741. charclass_handler, P(ccd));
  1742. ccd->button->generic.column = 1;
  1743. ctrl_columns(s, 1, 100);
  1744. /*
  1745. * The Window/Colours panel.
  1746. */
  1747. ctrl_settitle(b, "Window/Colours", "Options controlling use of colours");
  1748. s = ctrl_getset(b, "Window/Colours", "general",
  1749. "General options for colour usage");
  1750. ctrl_checkbox(s, "Allow terminal to specify ANSI colours", 'i',
  1751. HELPCTX(colours_ansi),
  1752. conf_checkbox_handler, I(CONF_ansi_colour));
  1753. ctrl_checkbox(s, "Allow terminal to use xterm 256-colour mode", '2',
  1754. HELPCTX(colours_xterm256), conf_checkbox_handler,
  1755. I(CONF_xterm_256_colour));
  1756. ctrl_radiobuttons(s, "Indicate bolded text by changing:", 'b', 3,
  1757. HELPCTX(colours_bold),
  1758. conf_radiobutton_handler, I(CONF_bold_style),
  1759. "The font", I(1),
  1760. "The colour", I(2),
  1761. "Both", I(3),
  1762. NULL);
  1763. str = dupprintf("Adjust the precise colours %s displays", appname);
  1764. s = ctrl_getset(b, "Window/Colours", "adjust", str);
  1765. sfree(str);
  1766. ctrl_text(s, "Select a colour from the list, and then click the"
  1767. " Modify button to change its appearance.",
  1768. HELPCTX(colours_config));
  1769. ctrl_columns(s, 2, 67, 33);
  1770. cd = (struct colour_data *)ctrl_alloc(b, sizeof(struct colour_data));
  1771. cd->listbox = ctrl_listbox(s, "Select a colour to adjust:", 'u',
  1772. HELPCTX(colours_config), colour_handler, P(cd));
  1773. cd->listbox->generic.column = 0;
  1774. cd->listbox->listbox.height = 7;
  1775. c = ctrl_text(s, "RGB value:", HELPCTX(colours_config));
  1776. c->generic.column = 1;
  1777. cd->redit = ctrl_editbox(s, "Red", 'r', 50, HELPCTX(colours_config),
  1778. colour_handler, P(cd), P(NULL));
  1779. cd->redit->generic.column = 1;
  1780. cd->gedit = ctrl_editbox(s, "Green", 'n', 50, HELPCTX(colours_config),
  1781. colour_handler, P(cd), P(NULL));
  1782. cd->gedit->generic.column = 1;
  1783. cd->bedit = ctrl_editbox(s, "Blue", 'e', 50, HELPCTX(colours_config),
  1784. colour_handler, P(cd), P(NULL));
  1785. cd->bedit->generic.column = 1;
  1786. cd->button = ctrl_pushbutton(s, "Modify", 'm', HELPCTX(colours_config),
  1787. colour_handler, P(cd));
  1788. cd->button->generic.column = 1;
  1789. ctrl_columns(s, 1, 100);
  1790. /*
  1791. * The Connection panel. This doesn't show up if we're in a
  1792. * non-network utility such as pterm. We tell this by being
  1793. * passed a protocol < 0.
  1794. */
  1795. if (protocol >= 0) {
  1796. ctrl_settitle(b, "Connection", "Options controlling the connection");
  1797. s = ctrl_getset(b, "Connection", "keepalive",
  1798. "Sending of null packets to keep session active");
  1799. ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
  1800. HELPCTX(connection_keepalive),
  1801. conf_editbox_handler, I(CONF_ping_interval),
  1802. I(-1));
  1803. if (!midsession) {
  1804. s = ctrl_getset(b, "Connection", "tcp",
  1805. "Low-level TCP connection options");
  1806. ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)",
  1807. 'n', HELPCTX(connection_nodelay),
  1808. conf_checkbox_handler,
  1809. I(CONF_tcp_nodelay));
  1810. ctrl_checkbox(s, "Enable TCP keepalives (SO_KEEPALIVE option)",
  1811. 'p', HELPCTX(connection_tcpkeepalive),
  1812. conf_checkbox_handler,
  1813. I(CONF_tcp_keepalives));
  1814. #ifndef NO_IPV6
  1815. s = ctrl_getset(b, "Connection", "ipversion",
  1816. "Internet protocol version");
  1817. ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
  1818. HELPCTX(connection_ipversion),
  1819. conf_radiobutton_handler,
  1820. I(CONF_addressfamily),
  1821. "Auto", 'u', I(ADDRTYPE_UNSPEC),
  1822. "IPv4", '4', I(ADDRTYPE_IPV4),
  1823. "IPv6", '6', I(ADDRTYPE_IPV6),
  1824. NULL);
  1825. #endif
  1826. {
  1827. const char *label = backend_from_proto(PROT_SSH) ?
  1828. "Logical name of remote host (e.g. for SSH key lookup):" :
  1829. "Logical name of remote host:";
  1830. s = ctrl_getset(b, "Connection", "identity",
  1831. "Logical name of remote host");
  1832. ctrl_editbox(s, label, 'm', 100,
  1833. HELPCTX(connection_loghost),
  1834. conf_editbox_handler, I(CONF_loghost), I(1));
  1835. }
  1836. }
  1837. /*
  1838. * A sub-panel Connection/Data, containing options that
  1839. * decide on data to send to the server.
  1840. */
  1841. if (!midsession) {
  1842. ctrl_settitle(b, "Connection/Data", "Data to send to the server");
  1843. s = ctrl_getset(b, "Connection/Data", "login",
  1844. "Login details");
  1845. ctrl_editbox(s, "Auto-login username", 'u', 50,
  1846. HELPCTX(connection_username),
  1847. conf_editbox_handler, I(CONF_username), I(1));
  1848. {
  1849. /* We assume the local username is sufficiently stable
  1850. * to include on the dialog box. */
  1851. char *user = get_username();
  1852. char *userlabel = dupprintf("Use system username (%s)",
  1853. user ? user : "");
  1854. sfree(user);
  1855. ctrl_radiobuttons(s, "When username is not specified:", 'n', 4,
  1856. HELPCTX(connection_username_from_env),
  1857. conf_radiobutton_handler,
  1858. I(CONF_username_from_env),
  1859. "Prompt", I(FALSE),
  1860. userlabel, I(TRUE),
  1861. NULL);
  1862. sfree(userlabel);
  1863. }
  1864. s = ctrl_getset(b, "Connection/Data", "term",
  1865. "Terminal details");
  1866. ctrl_editbox(s, "Terminal-type string", 't', 50,
  1867. HELPCTX(connection_termtype),
  1868. conf_editbox_handler, I(CONF_termtype), I(1));
  1869. ctrl_editbox(s, "Terminal speeds", 's', 50,
  1870. HELPCTX(connection_termspeed),
  1871. conf_editbox_handler, I(CONF_termspeed), I(1));
  1872. s = ctrl_getset(b, "Connection/Data", "env",
  1873. "Environment variables");
  1874. ctrl_columns(s, 2, 80, 20);
  1875. ed = (struct environ_data *)
  1876. ctrl_alloc(b, sizeof(struct environ_data));
  1877. ed->varbox = ctrl_editbox(s, "Variable", 'v', 60,
  1878. HELPCTX(telnet_environ),
  1879. environ_handler, P(ed), P(NULL));
  1880. ed->varbox->generic.column = 0;
  1881. ed->valbox = ctrl_editbox(s, "Value", 'l', 60,
  1882. HELPCTX(telnet_environ),
  1883. environ_handler, P(ed), P(NULL));
  1884. ed->valbox->generic.column = 0;
  1885. ed->addbutton = ctrl_pushbutton(s, "Add", 'd',
  1886. HELPCTX(telnet_environ),
  1887. environ_handler, P(ed));
  1888. ed->addbutton->generic.column = 1;
  1889. ed->rembutton = ctrl_pushbutton(s, "Remove", 'r',
  1890. HELPCTX(telnet_environ),
  1891. environ_handler, P(ed));
  1892. ed->rembutton->generic.column = 1;
  1893. ctrl_columns(s, 1, 100);
  1894. ed->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
  1895. HELPCTX(telnet_environ),
  1896. environ_handler, P(ed));
  1897. ed->listbox->listbox.height = 3;
  1898. ed->listbox->listbox.ncols = 2;
  1899. ed->listbox->listbox.percentages = snewn(2, int);
  1900. ed->listbox->listbox.percentages[0] = 30;
  1901. ed->listbox->listbox.percentages[1] = 70;
  1902. }
  1903. }
  1904. if (!midsession) {
  1905. /*
  1906. * The Connection/Proxy panel.
  1907. */
  1908. ctrl_settitle(b, "Connection/Proxy",
  1909. "Options controlling proxy usage");
  1910. s = ctrl_getset(b, "Connection/Proxy", "basics", NULL);
  1911. ctrl_radiobuttons(s, "Proxy type:", 't', 3,
  1912. HELPCTX(proxy_type),
  1913. conf_radiobutton_handler,
  1914. I(CONF_proxy_type),
  1915. "None", I(PROXY_NONE),
  1916. "SOCKS 4", I(PROXY_SOCKS4),
  1917. "SOCKS 5", I(PROXY_SOCKS5),
  1918. "HTTP", I(PROXY_HTTP),
  1919. "Telnet", I(PROXY_TELNET),
  1920. NULL);
  1921. ctrl_columns(s, 2, 80, 20);
  1922. c = ctrl_editbox(s, "Proxy hostname", 'y', 100,
  1923. HELPCTX(proxy_main),
  1924. conf_editbox_handler,
  1925. I(CONF_proxy_host), I(1));
  1926. c->generic.column = 0;
  1927. c = ctrl_editbox(s, "Port", 'p', 100,
  1928. HELPCTX(proxy_main),
  1929. conf_editbox_handler,
  1930. I(CONF_proxy_port),
  1931. I(-1));
  1932. c->generic.column = 1;
  1933. ctrl_columns(s, 1, 100);
  1934. ctrl_editbox(s, "Exclude Hosts/IPs", 'e', 100,
  1935. HELPCTX(proxy_exclude),
  1936. conf_editbox_handler,
  1937. I(CONF_proxy_exclude_list), I(1));
  1938. ctrl_checkbox(s, "Consider proxying local host connections", 'x',
  1939. HELPCTX(proxy_exclude),
  1940. conf_checkbox_handler,
  1941. I(CONF_even_proxy_localhost));
  1942. ctrl_radiobuttons(s, "Do DNS name lookup at proxy end:", 'd', 3,
  1943. HELPCTX(proxy_dns),
  1944. conf_radiobutton_handler,
  1945. I(CONF_proxy_dns),
  1946. "No", I(FORCE_OFF),
  1947. "Auto", I(AUTO),
  1948. "Yes", I(FORCE_ON), NULL);
  1949. ctrl_editbox(s, "Username", 'u', 60,
  1950. HELPCTX(proxy_auth),
  1951. conf_editbox_handler,
  1952. I(CONF_proxy_username), I(1));
  1953. c = ctrl_editbox(s, "Password", 'w', 60,
  1954. HELPCTX(proxy_auth),
  1955. conf_editbox_handler,
  1956. I(CONF_proxy_password), I(1));
  1957. c->editbox.password = 1;
  1958. ctrl_editbox(s, "Telnet command", 'm', 100,
  1959. HELPCTX(proxy_command),
  1960. conf_editbox_handler,
  1961. I(CONF_proxy_telnet_command), I(1));
  1962. ctrl_radiobuttons(s, "Print proxy diagnostics "
  1963. "in the terminal window", 'r', 5,
  1964. HELPCTX(proxy_main),
  1965. conf_radiobutton_handler,
  1966. I(CONF_proxy_log_to_term),
  1967. "No", I(FORCE_OFF),
  1968. "Yes", I(FORCE_ON),
  1969. "Only until session starts", I(AUTO), NULL);
  1970. }
  1971. /*
  1972. * The Telnet panel exists in the base config box, and in a
  1973. * mid-session reconfig box _if_ we're using Telnet.
  1974. */
  1975. if (!midsession || protocol == PROT_TELNET) {
  1976. /*
  1977. * The Connection/Telnet panel.
  1978. */
  1979. ctrl_settitle(b, "Connection/Telnet",
  1980. "Options controlling Telnet connections");
  1981. s = ctrl_getset(b, "Connection/Telnet", "protocol",
  1982. "Telnet protocol adjustments");
  1983. if (!midsession) {
  1984. ctrl_radiobuttons(s, "Handling of OLD_ENVIRON ambiguity:",
  1985. NO_SHORTCUT, 2,
  1986. HELPCTX(telnet_oldenviron),
  1987. conf_radiobutton_handler,
  1988. I(CONF_rfc_environ),
  1989. "BSD (commonplace)", 'b', I(0),
  1990. "RFC 1408 (unusual)", 'f', I(1), NULL);
  1991. ctrl_radiobuttons(s, "Telnet negotiation mode:", 't', 2,
  1992. HELPCTX(telnet_passive),
  1993. conf_radiobutton_handler,
  1994. I(CONF_passive_telnet),
  1995. "Passive", I(1), "Active", I(0), NULL);
  1996. }
  1997. ctrl_checkbox(s, "Keyboard sends Telnet special commands", 'k',
  1998. HELPCTX(telnet_specialkeys),
  1999. conf_checkbox_handler,
  2000. I(CONF_telnet_keyboard));
  2001. ctrl_checkbox(s, "Return key sends Telnet New Line instead of ^M",
  2002. 'm', HELPCTX(telnet_newline),
  2003. conf_checkbox_handler,
  2004. I(CONF_telnet_newline));
  2005. }
  2006. if (!midsession) {
  2007. /*
  2008. * The Connection/Rlogin panel.
  2009. */
  2010. ctrl_settitle(b, "Connection/Rlogin",
  2011. "Options controlling Rlogin connections");
  2012. s = ctrl_getset(b, "Connection/Rlogin", "data",
  2013. "Data to send to the server");
  2014. ctrl_editbox(s, "Local username:", 'l', 50,
  2015. HELPCTX(rlogin_localuser),
  2016. conf_editbox_handler, I(CONF_localusername), I(1));
  2017. }
  2018. /*
  2019. * All the SSH stuff is omitted in PuTTYtel, or in a reconfig
  2020. * when we're not doing SSH.
  2021. */
  2022. if (backend_from_proto(PROT_SSH) && (!midsession || protocol == PROT_SSH)) {
  2023. /*
  2024. * The Connection/SSH panel.
  2025. */
  2026. ctrl_settitle(b, "Connection/SSH",
  2027. "Options controlling SSH connections");
  2028. /* SSH-1 or connection-sharing downstream */
  2029. if (midsession && (protcfginfo == 1 || protcfginfo == -1)) {
  2030. s = ctrl_getset(b, "Connection/SSH", "disclaimer", NULL);
  2031. ctrl_text(s, "Nothing on this panel may be reconfigured in mid-"
  2032. "session; it is only here so that sub-panels of it can "
  2033. "exist without looking strange.", HELPCTX(no_help));
  2034. }
  2035. if (!midsession) {
  2036. s = ctrl_getset(b, "Connection/SSH", "data",
  2037. "Data to send to the server");
  2038. ctrl_editbox(s, "Remote command:", 'r', 100,
  2039. HELPCTX(ssh_command),
  2040. conf_editbox_handler, I(CONF_remote_cmd), I(1));
  2041. s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
  2042. ctrl_checkbox(s, "Don't start a shell or command at all", 'n',
  2043. HELPCTX(ssh_noshell),
  2044. conf_checkbox_handler,
  2045. I(CONF_ssh_no_shell));
  2046. }
  2047. if (!midsession || !(protcfginfo == 1 || protcfginfo == -1)) {
  2048. s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
  2049. ctrl_checkbox(s, "Enable compression", 'e',
  2050. HELPCTX(ssh_compress),
  2051. conf_checkbox_handler,
  2052. I(CONF_compression));
  2053. }
  2054. if (!midsession) {
  2055. s = ctrl_getset(b, "Connection/SSH", "sharing", "Sharing an SSH connection between PuTTY tools");
  2056. ctrl_checkbox(s, "Share SSH connections if possible", 's',
  2057. HELPCTX(ssh_share),
  2058. conf_checkbox_handler,
  2059. I(CONF_ssh_connection_sharing));
  2060. ctrl_text(s, "Permitted roles in a shared connection:",
  2061. HELPCTX(ssh_share));
  2062. ctrl_checkbox(s, "Upstream (connecting to the real server)", 'u',
  2063. HELPCTX(ssh_share),
  2064. conf_checkbox_handler,
  2065. I(CONF_ssh_connection_sharing_upstream));
  2066. ctrl_checkbox(s, "Downstream (connecting to the upstream PuTTY)", 'd',
  2067. HELPCTX(ssh_share),
  2068. conf_checkbox_handler,
  2069. I(CONF_ssh_connection_sharing_downstream));
  2070. }
  2071. if (!midsession) {
  2072. s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
  2073. ctrl_radiobuttons(s, "SSH protocol version:", NO_SHORTCUT, 2,
  2074. HELPCTX(ssh_protocol),
  2075. conf_radiobutton_handler,
  2076. I(CONF_sshprot),
  2077. "2", '2', I(3),
  2078. "1 (INSECURE)", '1', I(0), NULL);
  2079. }
  2080. /*
  2081. * The Connection/SSH/Kex panel. (Owing to repeat key
  2082. * exchange, much of this is meaningful in mid-session _if_
  2083. * we're using SSH-2 and are not a connection-sharing
  2084. * downstream, or haven't decided yet.)
  2085. */
  2086. if (protcfginfo != 1 && protcfginfo != -1) {
  2087. ctrl_settitle(b, "Connection/SSH/Kex",
  2088. "Options controlling SSH key exchange");
  2089. s = ctrl_getset(b, "Connection/SSH/Kex", "main",
  2090. "Key exchange algorithm options");
  2091. c = ctrl_draglist(s, "Algorithm selection policy:", 's',
  2092. HELPCTX(ssh_kexlist),
  2093. kexlist_handler, P(NULL));
  2094. c->listbox.height = 5;
  2095. s = ctrl_getset(b, "Connection/SSH/Kex", "repeat",
  2096. "Options controlling key re-exchange");
  2097. ctrl_editbox(s, "Max minutes before rekey (0 for no limit)", 't', 20,
  2098. HELPCTX(ssh_kex_repeat),
  2099. conf_editbox_handler,
  2100. I(CONF_ssh_rekey_time),
  2101. I(-1));
  2102. ctrl_editbox(s, "Max data before rekey (0 for no limit)", 'x', 20,
  2103. HELPCTX(ssh_kex_repeat),
  2104. conf_editbox_handler,
  2105. I(CONF_ssh_rekey_data),
  2106. I(16));
  2107. ctrl_text(s, "(Use 1M for 1 megabyte, 1G for 1 gigabyte etc)",
  2108. HELPCTX(ssh_kex_repeat));
  2109. }
  2110. /*
  2111. * The 'Connection/SSH/Host keys' panel.
  2112. */
  2113. if (protcfginfo != 1 && protcfginfo != -1) {
  2114. ctrl_settitle(b, "Connection/SSH/Host keys",
  2115. "Options controlling SSH host keys");
  2116. s = ctrl_getset(b, "Connection/SSH/Host keys", "main",
  2117. "Host key algorithm preference");
  2118. c = ctrl_draglist(s, "Algorithm selection policy:", 's',
  2119. HELPCTX(ssh_hklist),
  2120. hklist_handler, P(NULL));
  2121. c->listbox.height = 5;
  2122. }
  2123. /*
  2124. * Manual host key configuration is irrelevant mid-session,
  2125. * as we enforce that the host key for rekeys is the
  2126. * same as that used at the start of the session.
  2127. */
  2128. if (!midsession) {
  2129. s = ctrl_getset(b, "Connection/SSH/Host keys", "hostkeys",
  2130. "Manually configure host keys for this connection");
  2131. ctrl_columns(s, 2, 75, 25);
  2132. c = ctrl_text(s, "Host keys or fingerprints to accept:",
  2133. HELPCTX(ssh_kex_manual_hostkeys));
  2134. c->generic.column = 0;
  2135. /* You want to select from the list, _then_ hit Remove. So
  2136. * tab order should be that way round. */
  2137. mh = (struct manual_hostkey_data *)
  2138. ctrl_alloc(b,sizeof(struct manual_hostkey_data));
  2139. mh->rembutton = ctrl_pushbutton(s, "Remove", 'r',
  2140. HELPCTX(ssh_kex_manual_hostkeys),
  2141. manual_hostkey_handler, P(mh));
  2142. mh->rembutton->generic.column = 1;
  2143. mh->rembutton->generic.tabdelay = 1;
  2144. mh->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
  2145. HELPCTX(ssh_kex_manual_hostkeys),
  2146. manual_hostkey_handler, P(mh));
  2147. /* This list box can't be very tall, because there's not
  2148. * much room in the pane on Windows at least. This makes
  2149. * it become really unhelpful if a horizontal scrollbar
  2150. * appears, so we suppress that. */
  2151. mh->listbox->listbox.height = 2;
  2152. mh->listbox->listbox.hscroll = FALSE;
  2153. ctrl_tabdelay(s, mh->rembutton);
  2154. mh->keybox = ctrl_editbox(s, "Key", 'k', 80,
  2155. HELPCTX(ssh_kex_manual_hostkeys),
  2156. manual_hostkey_handler, P(mh), P(NULL));
  2157. mh->keybox->generic.column = 0;
  2158. mh->addbutton = ctrl_pushbutton(s, "Add key", 'y',
  2159. HELPCTX(ssh_kex_manual_hostkeys),
  2160. manual_hostkey_handler, P(mh));
  2161. mh->addbutton->generic.column = 1;
  2162. ctrl_columns(s, 1, 100);
  2163. }
  2164. if (!midsession || !(protcfginfo == 1 || protcfginfo == -1)) {
  2165. /*
  2166. * The Connection/SSH/Cipher panel.
  2167. */
  2168. ctrl_settitle(b, "Connection/SSH/Cipher",
  2169. "Options controlling SSH encryption");
  2170. s = ctrl_getset(b, "Connection/SSH/Cipher",
  2171. "encryption", "Encryption options");
  2172. c = ctrl_draglist(s, "Encryption cipher selection policy:", 's',
  2173. HELPCTX(ssh_ciphers),
  2174. cipherlist_handler, P(NULL));
  2175. c->listbox.height = 6;
  2176. ctrl_checkbox(s, "Enable legacy use of single-DES in SSH-2", 'i',
  2177. HELPCTX(ssh_ciphers),
  2178. conf_checkbox_handler,
  2179. I(CONF_ssh2_des_cbc));
  2180. }
  2181. if (!midsession) {
  2182. /*
  2183. * The Connection/SSH/Auth panel.
  2184. */
  2185. ctrl_settitle(b, "Connection/SSH/Auth",
  2186. "Options controlling SSH authentication");
  2187. s = ctrl_getset(b, "Connection/SSH/Auth", "main", NULL);
  2188. ctrl_checkbox(s, "Display pre-authentication banner (SSH-2 only)",
  2189. 'd', HELPCTX(ssh_auth_banner),
  2190. conf_checkbox_handler,
  2191. I(CONF_ssh_show_banner));
  2192. ctrl_checkbox(s, "Bypass authentication entirely (SSH-2 only)", 'b',
  2193. HELPCTX(ssh_auth_bypass),
  2194. conf_checkbox_handler,
  2195. I(CONF_ssh_no_userauth));
  2196. s = ctrl_getset(b, "Connection/SSH/Auth", "methods",
  2197. "Authentication methods");
  2198. ctrl_checkbox(s, "Attempt authentication using Pageant", 'p',
  2199. HELPCTX(ssh_auth_pageant),
  2200. conf_checkbox_handler,
  2201. I(CONF_tryagent));
  2202. ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH-1)", 'm',
  2203. HELPCTX(ssh_auth_tis),
  2204. conf_checkbox_handler,
  2205. I(CONF_try_tis_auth));
  2206. ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH-2)",
  2207. 'i', HELPCTX(ssh_auth_ki),
  2208. conf_checkbox_handler,
  2209. I(CONF_try_ki_auth));
  2210. s = ctrl_getset(b, "Connection/SSH/Auth", "params",
  2211. "Authentication parameters");
  2212. ctrl_checkbox(s, "Allow agent forwarding", 'f',
  2213. HELPCTX(ssh_auth_agentfwd),
  2214. conf_checkbox_handler, I(CONF_agentfwd));
  2215. ctrl_checkbox(s, "Allow attempted changes of username in SSH-2", NO_SHORTCUT,
  2216. HELPCTX(ssh_auth_changeuser),
  2217. conf_checkbox_handler,
  2218. I(CONF_change_username));
  2219. ctrl_filesel(s, "Private key file for authentication:", 'k',
  2220. FILTER_KEY_FILES, FALSE, "Select private key file",
  2221. HELPCTX(ssh_auth_privkey),
  2222. conf_filesel_handler, I(CONF_keyfile));
  2223. #ifndef NO_GSSAPI
  2224. /*
  2225. * Connection/SSH/Auth/GSSAPI, which sadly won't fit on
  2226. * the main Auth panel.
  2227. */
  2228. ctrl_settitle(b, "Connection/SSH/Auth/GSSAPI",
  2229. "Options controlling GSSAPI authentication");
  2230. s = ctrl_getset(b, "Connection/SSH/Auth/GSSAPI", "gssapi", NULL);
  2231. ctrl_checkbox(s, "Attempt GSSAPI authentication (SSH-2 only)",
  2232. 't', HELPCTX(ssh_gssapi),
  2233. conf_checkbox_handler,
  2234. I(CONF_try_gssapi_auth));
  2235. ctrl_checkbox(s, "Allow GSSAPI credential delegation", 'l',
  2236. HELPCTX(ssh_gssapi_delegation),
  2237. conf_checkbox_handler,
  2238. I(CONF_gssapifwd));
  2239. /*
  2240. * GSSAPI library selection.
  2241. */
  2242. if (ngsslibs > 1) {
  2243. c = ctrl_draglist(s, "Preference order for GSSAPI libraries:",
  2244. 'p', HELPCTX(ssh_gssapi_libraries),
  2245. gsslist_handler, P(NULL));
  2246. c->listbox.height = ngsslibs;
  2247. /*
  2248. * I currently assume that if more than one GSS
  2249. * library option is available, then one of them is
  2250. * 'user-supplied' and so we should present the
  2251. * following file selector. This is at least half-
  2252. * reasonable, because if we're using statically
  2253. * linked GSSAPI then there will only be one option
  2254. * and no way to load from a user-supplied library,
  2255. * whereas if we're using dynamic libraries then
  2256. * there will almost certainly be some default
  2257. * option in addition to a user-supplied path. If
  2258. * anyone ever ports PuTTY to a system on which
  2259. * dynamic-library GSSAPI is available but there is
  2260. * absolutely no consensus on where to keep the
  2261. * libraries, there'll need to be a flag alongside
  2262. * ngsslibs to control whether the file selector is
  2263. * displayed.
  2264. */
  2265. ctrl_filesel(s, "User-supplied GSSAPI library path:", 's',
  2266. FILTER_DYNLIB_FILES, FALSE, "Select library file",
  2267. HELPCTX(ssh_gssapi_libraries),
  2268. conf_filesel_handler,
  2269. I(CONF_ssh_gss_custom));
  2270. }
  2271. #endif
  2272. }
  2273. if (!midsession) {
  2274. /*
  2275. * The Connection/SSH/TTY panel.
  2276. */
  2277. ctrl_settitle(b, "Connection/SSH/TTY", "Remote terminal settings");
  2278. s = ctrl_getset(b, "Connection/SSH/TTY", "sshtty", NULL);
  2279. ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p',
  2280. HELPCTX(ssh_nopty),
  2281. conf_checkbox_handler,
  2282. I(CONF_nopty));
  2283. s = ctrl_getset(b, "Connection/SSH/TTY", "ttymodes",
  2284. "Terminal modes");
  2285. td = (struct ttymodes_data *)
  2286. ctrl_alloc(b, sizeof(struct ttymodes_data));
  2287. ctrl_columns(s, 2, 75, 25);
  2288. c = ctrl_text(s, "Terminal modes to send:", HELPCTX(ssh_ttymodes));
  2289. c->generic.column = 0;
  2290. td->rembutton = ctrl_pushbutton(s, "Remove", 'r',
  2291. HELPCTX(ssh_ttymodes),
  2292. ttymodes_handler, P(td));
  2293. td->rembutton->generic.column = 1;
  2294. td->rembutton->generic.tabdelay = 1;
  2295. ctrl_columns(s, 1, 100);
  2296. td->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
  2297. HELPCTX(ssh_ttymodes),
  2298. ttymodes_handler, P(td));
  2299. td->listbox->listbox.multisel = 1;
  2300. td->listbox->listbox.height = 4;
  2301. td->listbox->listbox.ncols = 2;
  2302. td->listbox->listbox.percentages = snewn(2, int);
  2303. td->listbox->listbox.percentages[0] = 40;
  2304. td->listbox->listbox.percentages[1] = 60;
  2305. ctrl_tabdelay(s, td->rembutton);
  2306. ctrl_columns(s, 2, 75, 25);
  2307. td->modelist = ctrl_droplist(s, "Mode:", 'm', 67,
  2308. HELPCTX(ssh_ttymodes),
  2309. ttymodes_handler, P(td));
  2310. td->modelist->generic.column = 0;
  2311. td->addbutton = ctrl_pushbutton(s, "Add", 'd',
  2312. HELPCTX(ssh_ttymodes),
  2313. ttymodes_handler, P(td));
  2314. td->addbutton->generic.column = 1;
  2315. td->addbutton->generic.tabdelay = 1;
  2316. ctrl_columns(s, 1, 100); /* column break */
  2317. /* Bit of a hack to get the value radio buttons and
  2318. * edit-box on the same row. */
  2319. ctrl_columns(s, 3, 25, 50, 25);
  2320. c = ctrl_text(s, "Value:", HELPCTX(ssh_ttymodes));
  2321. c->generic.column = 0;
  2322. td->valradio = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 2,
  2323. HELPCTX(ssh_ttymodes),
  2324. ttymodes_handler, P(td),
  2325. "Auto", NO_SHORTCUT, P(NULL),
  2326. "This:", NO_SHORTCUT, P(NULL),
  2327. NULL);
  2328. td->valradio->generic.column = 1;
  2329. td->valbox = ctrl_editbox(s, NULL, NO_SHORTCUT, 100,
  2330. HELPCTX(ssh_ttymodes),
  2331. ttymodes_handler, P(td), P(NULL));
  2332. td->valbox->generic.column = 2;
  2333. ctrl_tabdelay(s, td->addbutton);
  2334. }
  2335. if (!midsession) {
  2336. /*
  2337. * The Connection/SSH/X11 panel.
  2338. */
  2339. ctrl_settitle(b, "Connection/SSH/X11",
  2340. "Options controlling SSH X11 forwarding");
  2341. s = ctrl_getset(b, "Connection/SSH/X11", "x11", "X11 forwarding");
  2342. ctrl_checkbox(s, "Enable X11 forwarding", 'e',
  2343. HELPCTX(ssh_tunnels_x11),
  2344. conf_checkbox_handler,I(CONF_x11_forward));
  2345. ctrl_editbox(s, "X display location", 'x', 50,
  2346. HELPCTX(ssh_tunnels_x11),
  2347. conf_editbox_handler, I(CONF_x11_display), I(1));
  2348. ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2,
  2349. HELPCTX(ssh_tunnels_x11auth),
  2350. conf_radiobutton_handler,
  2351. I(CONF_x11_auth),
  2352. "MIT-Magic-Cookie-1", I(X11_MIT),
  2353. "XDM-Authorization-1", I(X11_XDM), NULL);
  2354. }
  2355. /*
  2356. * The Tunnels panel _is_ still available in mid-session.
  2357. */
  2358. ctrl_settitle(b, "Connection/SSH/Tunnels",
  2359. "Options controlling SSH port forwarding");
  2360. s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd",
  2361. "Port forwarding");
  2362. ctrl_checkbox(s, "Local ports accept connections from other hosts",'t',
  2363. HELPCTX(ssh_tunnels_portfwd_localhost),
  2364. conf_checkbox_handler,
  2365. I(CONF_lport_acceptall));
  2366. ctrl_checkbox(s, "Remote ports do the same (SSH-2 only)", 'p',
  2367. HELPCTX(ssh_tunnels_portfwd_localhost),
  2368. conf_checkbox_handler,
  2369. I(CONF_rport_acceptall));
  2370. ctrl_columns(s, 3, 55, 20, 25);
  2371. c = ctrl_text(s, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd));
  2372. c->generic.column = COLUMN_FIELD(0,2);
  2373. /* You want to select from the list, _then_ hit Remove. So tab order
  2374. * should be that way round. */
  2375. pfd = (struct portfwd_data *)ctrl_alloc(b,sizeof(struct portfwd_data));
  2376. pfd->rembutton = ctrl_pushbutton(s, "Remove", 'r',
  2377. HELPCTX(ssh_tunnels_portfwd),
  2378. portfwd_handler, P(pfd));
  2379. pfd->rembutton->generic.column = 2;
  2380. pfd->rembutton->generic.tabdelay = 1;
  2381. pfd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
  2382. HELPCTX(ssh_tunnels_portfwd),
  2383. portfwd_handler, P(pfd));
  2384. pfd->listbox->listbox.height = 3;
  2385. pfd->listbox->listbox.ncols = 2;
  2386. pfd->listbox->listbox.percentages = snewn(2, int);
  2387. pfd->listbox->listbox.percentages[0] = 20;
  2388. pfd->listbox->listbox.percentages[1] = 80;
  2389. ctrl_tabdelay(s, pfd->rembutton);
  2390. ctrl_text(s, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd));
  2391. /* You want to enter source, destination and type, _then_ hit Add.
  2392. * Again, we adjust the tab order to reflect this. */
  2393. pfd->addbutton = ctrl_pushbutton(s, "Add", 'd',
  2394. HELPCTX(ssh_tunnels_portfwd),
  2395. portfwd_handler, P(pfd));
  2396. pfd->addbutton->generic.column = 2;
  2397. pfd->addbutton->generic.tabdelay = 1;
  2398. pfd->sourcebox = ctrl_editbox(s, "Source port", 's', 40,
  2399. HELPCTX(ssh_tunnels_portfwd),
  2400. portfwd_handler, P(pfd), P(NULL));
  2401. pfd->sourcebox->generic.column = 0;
  2402. pfd->destbox = ctrl_editbox(s, "Destination", 'i', 67,
  2403. HELPCTX(ssh_tunnels_portfwd),
  2404. portfwd_handler, P(pfd), P(NULL));
  2405. pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
  2406. HELPCTX(ssh_tunnels_portfwd),
  2407. portfwd_handler, P(pfd),
  2408. "Local", 'l', P(NULL),
  2409. "Remote", 'm', P(NULL),
  2410. "Dynamic", 'y', P(NULL),
  2411. NULL);
  2412. #ifndef NO_IPV6
  2413. pfd->addressfamily =
  2414. ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
  2415. HELPCTX(ssh_tunnels_portfwd_ipversion),
  2416. portfwd_handler, P(pfd),
  2417. "Auto", 'u', I(ADDRTYPE_UNSPEC),
  2418. "IPv4", '4', I(ADDRTYPE_IPV4),
  2419. "IPv6", '6', I(ADDRTYPE_IPV6),
  2420. NULL);
  2421. #endif
  2422. ctrl_tabdelay(s, pfd->addbutton);
  2423. ctrl_columns(s, 1, 100);
  2424. if (!midsession) {
  2425. /*
  2426. * The Connection/SSH/Bugs panels.
  2427. */
  2428. ctrl_settitle(b, "Connection/SSH/Bugs",
  2429. "Workarounds for SSH server bugs");
  2430. s = ctrl_getset(b, "Connection/SSH/Bugs", "main",
  2431. "Detection of known bugs in SSH servers");
  2432. ctrl_droplist(s, "Chokes on SSH-2 ignore messages", '2', 20,
  2433. HELPCTX(ssh_bugs_ignore2),
  2434. sshbug_handler, I(CONF_sshbug_ignore2));
  2435. ctrl_droplist(s, "Handles SSH-2 key re-exchange badly", 'k', 20,
  2436. HELPCTX(ssh_bugs_rekey2),
  2437. sshbug_handler, I(CONF_sshbug_rekey2));
  2438. ctrl_droplist(s, "Chokes on PuTTY's SSH-2 'winadj' requests", 'j',
  2439. 20, HELPCTX(ssh_bugs_winadj),
  2440. sshbug_handler, I(CONF_sshbug_winadj));
  2441. ctrl_droplist(s, "Replies to requests on closed channels", 'q', 20,
  2442. HELPCTX(ssh_bugs_chanreq),
  2443. sshbug_handler, I(CONF_sshbug_chanreq));
  2444. ctrl_droplist(s, "Ignores SSH-2 maximum packet size", 'x', 20,
  2445. HELPCTX(ssh_bugs_maxpkt2),
  2446. sshbug_handler, I(CONF_sshbug_maxpkt2));
  2447. ctrl_settitle(b, "Connection/SSH/More bugs",
  2448. "Further workarounds for SSH server bugs");
  2449. s = ctrl_getset(b, "Connection/SSH/More bugs", "main",
  2450. "Detection of known bugs in SSH servers");
  2451. ctrl_droplist(s, "Requires padding on SSH-2 RSA signatures", 'p', 20,
  2452. HELPCTX(ssh_bugs_rsapad2),
  2453. sshbug_handler, I(CONF_sshbug_rsapad2));
  2454. ctrl_droplist(s, "Only supports pre-RFC4419 SSH-2 DH GEX", 'd', 20,
  2455. HELPCTX(ssh_bugs_oldgex2),
  2456. sshbug_handler, I(CONF_sshbug_oldgex2));
  2457. ctrl_droplist(s, "Miscomputes SSH-2 HMAC keys", 'm', 20,
  2458. HELPCTX(ssh_bugs_hmac2),
  2459. sshbug_handler, I(CONF_sshbug_hmac2));
  2460. ctrl_droplist(s, "Misuses the session ID in SSH-2 PK auth", 'n', 20,
  2461. HELPCTX(ssh_bugs_pksessid2),
  2462. sshbug_handler, I(CONF_sshbug_pksessid2));
  2463. ctrl_droplist(s, "Miscomputes SSH-2 encryption keys", 'e', 20,
  2464. HELPCTX(ssh_bugs_derivekey2),
  2465. sshbug_handler, I(CONF_sshbug_derivekey2));
  2466. ctrl_droplist(s, "Chokes on SSH-1 ignore messages", 'i', 20,
  2467. HELPCTX(ssh_bugs_ignore1),
  2468. sshbug_handler, I(CONF_sshbug_ignore1));
  2469. ctrl_droplist(s, "Refuses all SSH-1 password camouflage", 's', 20,
  2470. HELPCTX(ssh_bugs_plainpw1),
  2471. sshbug_handler, I(CONF_sshbug_plainpw1));
  2472. ctrl_droplist(s, "Chokes on SSH-1 RSA authentication", 'r', 20,
  2473. HELPCTX(ssh_bugs_rsa1),
  2474. sshbug_handler, I(CONF_sshbug_rsa1));
  2475. }
  2476. }
  2477. }