config.c 135 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340
  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. #include "tree234.h"
  11. #define PRINTER_DISABLED_STRING "None (printing disabled)"
  12. #define HOST_BOX_TITLE "Host Name (or IP address)"
  13. #define PORT_BOX_TITLE "Port"
  14. void conf_radiobutton_handler(dlgcontrol *ctrl, dlgparam *dlg,
  15. void *data, int event)
  16. {
  17. int button;
  18. Conf *conf = (Conf *)data;
  19. /*
  20. * For a standard radio button set, the context parameter gives
  21. * the primary key (CONF_foo), and the extra data per button
  22. * gives the value the target field should take if that button
  23. * is the one selected.
  24. */
  25. if (event == EVENT_REFRESH) {
  26. int val = conf_get_int(conf, ctrl->context.i);
  27. for (button = 0; button < ctrl->radio.nbuttons; button++)
  28. if (val == ctrl->radio.buttondata[button].i)
  29. break;
  30. /* We expected that `break' to happen, in all circumstances. */
  31. assert(button < ctrl->radio.nbuttons);
  32. dlg_radiobutton_set(ctrl, dlg, button);
  33. } else if (event == EVENT_VALCHANGE) {
  34. button = dlg_radiobutton_get(ctrl, dlg);
  35. assert(button >= 0 && button < ctrl->radio.nbuttons);
  36. conf_set_int(conf, ctrl->context.i,
  37. ctrl->radio.buttondata[button].i);
  38. }
  39. }
  40. void conf_radiobutton_bool_handler(dlgcontrol *ctrl, dlgparam *dlg,
  41. void *data, int event)
  42. {
  43. int button;
  44. Conf *conf = (Conf *)data;
  45. /*
  46. * Same as conf_radiobutton_handler, but using conf_set_bool in
  47. * place of conf_set_int, because it's dealing with a bool-typed
  48. * config option.
  49. */
  50. if (event == EVENT_REFRESH) {
  51. int val = conf_get_bool(conf, ctrl->context.i);
  52. for (button = 0; button < ctrl->radio.nbuttons; button++)
  53. if (val == ctrl->radio.buttondata[button].i)
  54. break;
  55. /* We expected that `break' to happen, in all circumstances. */
  56. assert(button < ctrl->radio.nbuttons);
  57. dlg_radiobutton_set(ctrl, dlg, button);
  58. } else if (event == EVENT_VALCHANGE) {
  59. button = dlg_radiobutton_get(ctrl, dlg);
  60. assert(button >= 0 && button < ctrl->radio.nbuttons);
  61. conf_set_bool(conf, ctrl->context.i,
  62. ctrl->radio.buttondata[button].i);
  63. }
  64. }
  65. #define CHECKBOX_INVERT (1<<30)
  66. void conf_checkbox_handler(dlgcontrol *ctrl, dlgparam *dlg,
  67. void *data, int event)
  68. {
  69. int key;
  70. bool invert;
  71. Conf *conf = (Conf *)data;
  72. /*
  73. * For a standard checkbox, the context parameter gives the
  74. * primary key (CONF_foo), optionally ORed with CHECKBOX_INVERT.
  75. */
  76. key = ctrl->context.i;
  77. if (key & CHECKBOX_INVERT) {
  78. key &= ~CHECKBOX_INVERT;
  79. invert = true;
  80. } else
  81. invert = false;
  82. /*
  83. * C lacks a logical XOR, so the following code uses the idiom
  84. * (!a ^ !b) to obtain the logical XOR of a and b. (That is, 1
  85. * iff exactly one of a and b is nonzero, otherwise 0.)
  86. */
  87. if (event == EVENT_REFRESH) {
  88. bool val = conf_get_bool(conf, key);
  89. dlg_checkbox_set(ctrl, dlg, (!val ^ !invert));
  90. } else if (event == EVENT_VALCHANGE) {
  91. conf_set_bool(conf, key, !dlg_checkbox_get(ctrl,dlg) ^ !invert);
  92. }
  93. }
  94. const struct conf_editbox_handler_type conf_editbox_str = {.type = EDIT_STR};
  95. const struct conf_editbox_handler_type conf_editbox_int = {.type = EDIT_INT};
  96. void conf_editbox_handler(dlgcontrol *ctrl, dlgparam *dlg,
  97. void *data, int event)
  98. {
  99. /*
  100. * The standard edit-box handler expects the main `context' field
  101. * to contain the primary key. The secondary `context2' field is a
  102. * pointer to the struct conf_editbox_handler_type defined in
  103. * putty.h.
  104. */
  105. int key = ctrl->context.i;
  106. const struct conf_editbox_handler_type *type = ctrl->context2.cp;
  107. Conf *conf = (Conf *)data;
  108. if (type->type == EDIT_STR) {
  109. if (event == EVENT_REFRESH) {
  110. char *field = conf_get_str(conf, key);
  111. dlg_editbox_set(ctrl, dlg, field);
  112. } else if (event == EVENT_VALCHANGE) {
  113. char *field = dlg_editbox_get(ctrl, dlg);
  114. conf_set_str(conf, key, field);
  115. sfree(field);
  116. }
  117. } else {
  118. if (event == EVENT_REFRESH) {
  119. char str[80];
  120. int value = conf_get_int(conf, key);
  121. if (type->type == EDIT_INT)
  122. sprintf(str, "%d", value);
  123. else
  124. sprintf(str, "%g", (double)value / type->denominator);
  125. dlg_editbox_set(ctrl, dlg, str);
  126. } else if (event == EVENT_VALCHANGE) {
  127. char *str = dlg_editbox_get(ctrl, dlg);
  128. if (type->type == EDIT_INT)
  129. conf_set_int(conf, key, atoi(str));
  130. else
  131. conf_set_int(conf, key, (int)(type->denominator * atof(str)));
  132. sfree(str);
  133. }
  134. }
  135. }
  136. void conf_filesel_handler(dlgcontrol *ctrl, dlgparam *dlg,
  137. void *data, int event)
  138. {
  139. int key = ctrl->context.i;
  140. Conf *conf = (Conf *)data;
  141. if (event == EVENT_REFRESH) {
  142. dlg_filesel_set(
  143. ctrl, dlg, conf_get_filename(conf, key));
  144. } else if (event == EVENT_VALCHANGE) {
  145. Filename *filename = dlg_filesel_get(ctrl, dlg);
  146. conf_set_filename(conf, key, filename);
  147. filename_free(filename);
  148. }
  149. }
  150. void conf_fontsel_handler(dlgcontrol *ctrl, dlgparam *dlg,
  151. void *data, int event)
  152. {
  153. int key = ctrl->context.i;
  154. Conf *conf = (Conf *)data;
  155. if (event == EVENT_REFRESH) {
  156. dlg_fontsel_set(
  157. ctrl, dlg, conf_get_fontspec(conf, key));
  158. } else if (event == EVENT_VALCHANGE) {
  159. FontSpec *fontspec = dlg_fontsel_get(ctrl, dlg);
  160. conf_set_fontspec(conf, key, fontspec);
  161. fontspec_free(fontspec);
  162. }
  163. }
  164. static void config_host_handler(dlgcontrol *ctrl, dlgparam *dlg,
  165. void *data, int event)
  166. {
  167. Conf *conf = (Conf *)data;
  168. /*
  169. * This function works just like the standard edit box handler,
  170. * only it has to choose the control's label and text from two
  171. * different places depending on the protocol.
  172. */
  173. if (event == EVENT_REFRESH) {
  174. if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL) {
  175. /*
  176. * This label text is carefully chosen to contain an n,
  177. * since that's the shortcut for the host name control.
  178. */
  179. dlg_label_change(ctrl, dlg, "Serial line");
  180. dlg_editbox_set(ctrl, dlg, conf_get_str(conf, CONF_serline));
  181. } else {
  182. dlg_label_change(ctrl, dlg, HOST_BOX_TITLE);
  183. dlg_editbox_set(ctrl, dlg, conf_get_str(conf, CONF_host));
  184. }
  185. } else if (event == EVENT_VALCHANGE) {
  186. char *s = dlg_editbox_get(ctrl, dlg);
  187. if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL)
  188. conf_set_str(conf, CONF_serline, s);
  189. else
  190. conf_set_str(conf, CONF_host, s);
  191. sfree(s);
  192. }
  193. }
  194. static void config_port_handler(dlgcontrol *ctrl, dlgparam *dlg,
  195. void *data, int event)
  196. {
  197. Conf *conf = (Conf *)data;
  198. char buf[80];
  199. /*
  200. * This function works similarly to the standard edit box handler,
  201. * only it has to choose the control's label and text from two
  202. * different places depending on the protocol.
  203. */
  204. if (event == EVENT_REFRESH) {
  205. if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL) {
  206. /*
  207. * This label text is carefully chosen to contain a p,
  208. * since that's the shortcut for the port control.
  209. */
  210. dlg_label_change(ctrl, dlg, "Speed");
  211. sprintf(buf, "%d", conf_get_int(conf, CONF_serspeed));
  212. } else {
  213. dlg_label_change(ctrl, dlg, PORT_BOX_TITLE);
  214. if (conf_get_int(conf, CONF_port) != 0)
  215. sprintf(buf, "%d", conf_get_int(conf, CONF_port));
  216. else
  217. /* Display an (invalid) port of 0 as blank */
  218. buf[0] = '\0';
  219. }
  220. dlg_editbox_set(ctrl, dlg, buf);
  221. } else if (event == EVENT_VALCHANGE) {
  222. char *s = dlg_editbox_get(ctrl, dlg);
  223. int i = atoi(s);
  224. sfree(s);
  225. if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL)
  226. conf_set_int(conf, CONF_serspeed, i);
  227. else
  228. conf_set_int(conf, CONF_port, i);
  229. }
  230. }
  231. struct hostport {
  232. dlgcontrol *host, *port, *protradio, *protlist;
  233. bool mid_refresh;
  234. };
  235. /*
  236. * Shared handler for protocol radio-button and drop-list controls.
  237. * Handles the interaction of those two controls, and also changes
  238. * the setting of the port box to match the protocol if necessary,
  239. * and refreshes both host and port boxes when switching to/from the
  240. * serial backend.
  241. */
  242. static void config_protocols_handler(dlgcontrol *ctrl, dlgparam *dlg,
  243. void *data, int event)
  244. {
  245. Conf *conf = (Conf *)data;
  246. int curproto = conf_get_int(conf, CONF_protocol);
  247. struct hostport *hp = (struct hostport *)ctrl->context.p;
  248. if (event == EVENT_REFRESH) {
  249. /*
  250. * Refresh the states of the controls from Conf.
  251. *
  252. * When refreshing these controls, we have to watch out for
  253. * re-entrancy: because there are two controls involved, the
  254. * refresh is not atomic, so the VALCHANGE and/or SELCHANGE
  255. * callbacks resulting from our updates here might cause other
  256. * settings here to change unwantedly. (E.g. setting the list
  257. * selection shouldn't trigger the SELCHANGE side effect of
  258. * selecting the Other radio button; setting the radio button
  259. * to Other here shouldn't have the side effect of selecting
  260. * whatever protocol is _currently_ selected in the list box,
  261. * if we haven't selected the right one yet.)
  262. */
  263. hp->mid_refresh = true;
  264. if (ctrl == hp->protradio) {
  265. /* Available buttons were set up when control was created.
  266. * Just select one of them, possibly. */
  267. for (int button = 0; button < ctrl->radio.nbuttons; button++)
  268. /* The final button is "Other:". If we reach that one, the
  269. * current protocol must be in the drop list, so we should
  270. * select the "Other:" button. */
  271. if (curproto == ctrl->radio.buttondata[button].i ||
  272. button == ctrl->radio.nbuttons-1) {
  273. dlg_radiobutton_set(ctrl, dlg, button);
  274. break;
  275. }
  276. } else if (ctrl == hp->protlist) {
  277. int curentry = -1;
  278. dlg_update_start(ctrl, dlg);
  279. dlg_listbox_clear(ctrl, dlg);
  280. assert(n_ui_backends > 0 && n_ui_backends < PROTOCOL_LIMIT);
  281. for (size_t i = n_ui_backends;
  282. i < PROTOCOL_LIMIT && backends[i]; i++) {
  283. dlg_listbox_addwithid(ctrl, dlg,
  284. backends[i]->displayname_tc,
  285. backends[i]->protocol);
  286. if (backends[i]->protocol == curproto)
  287. curentry = i - n_ui_backends;
  288. }
  289. if (curentry > 0) {
  290. /*
  291. * The currently configured protocol is one of the
  292. * list-box ones, so select it in protlist.
  293. *
  294. * (The corresponding refresh event for protradio
  295. * should have selected the "Other:" radio button, to
  296. * keep things consistent.)
  297. */
  298. dlg_listbox_select(ctrl, dlg, curentry);
  299. } else {
  300. /*
  301. * If the currently configured protocol is one of the
  302. * radio buttons, we must still ensure *something* is
  303. * selected in the list box. The sensible default is
  304. * the first list element, which be_*.c ought to have
  305. * arranged to be the 'runner-up' in protocol
  306. * popularity out of the ones relegated to the list
  307. * box.
  308. *
  309. * We don't make much effort to retain the state of
  310. * the list box when it doesn't correspond to an
  311. * actual protocol. So it's easy for this case to be
  312. * reached as a side effect of other actions, e.g.
  313. * loading a saved session that has a radio-button
  314. * protocol configured.
  315. */
  316. dlg_listbox_select(ctrl, dlg, 0);
  317. }
  318. dlg_update_done(ctrl, dlg);
  319. }
  320. hp->mid_refresh = false;
  321. } else if (!hp->mid_refresh) {
  322. /*
  323. * Potentially update Conf from the states of the controls.
  324. */
  325. int newproto = curproto;
  326. if (event == EVENT_VALCHANGE && ctrl == hp->protradio) {
  327. int button = dlg_radiobutton_get(ctrl, dlg);
  328. assert(button >= 0 && button < ctrl->radio.nbuttons);
  329. if (ctrl->radio.buttondata[button].i == -1) {
  330. /*
  331. * The 'Other' radio button was selected, which means we
  332. * have to set CONF_protocol based on the currently
  333. * selected list box entry.
  334. *
  335. * (We conditionalise this on there _being_ a selected
  336. * list box entry. I hope the case where nothing is
  337. * selected can't actually come up except during
  338. * initialisation, and I also hope that hp->mid_session
  339. * will prevent that case from getting here. But as a
  340. * last-ditch fallback, this if statement should at least
  341. * guarantee that we don't pass a nonsense value to
  342. * dlg_listbox_getid.)
  343. */
  344. int i = dlg_listbox_index(hp->protlist, dlg);
  345. if (i >= 0)
  346. newproto = dlg_listbox_getid(hp->protlist, dlg, i);
  347. } else {
  348. newproto = ctrl->radio.buttondata[button].i;
  349. }
  350. } else if (event == EVENT_SELCHANGE && ctrl == hp->protlist) {
  351. int i = dlg_listbox_index(ctrl, dlg);
  352. if (i >= 0) {
  353. newproto = dlg_listbox_getid(ctrl, dlg, i);
  354. /* Select the "Other" radio button, too */
  355. dlg_radiobutton_set(hp->protradio, dlg,
  356. hp->protradio->radio.nbuttons-1);
  357. }
  358. }
  359. if (newproto != curproto) {
  360. conf_set_int(conf, CONF_protocol, newproto);
  361. const struct BackendVtable *cvt = backend_vt_from_proto(curproto);
  362. const struct BackendVtable *nvt = backend_vt_from_proto(newproto);
  363. assert(cvt);
  364. assert(nvt);
  365. /*
  366. * Iff the user hasn't changed the port from the old
  367. * protocol's default, update it with the new protocol's
  368. * default.
  369. *
  370. * (This includes a "default" of 0, implying that there is
  371. * no sensible default for that protocol; in this case
  372. * it's displayed as a blank.)
  373. *
  374. * This helps with the common case of tabbing through the
  375. * controls in order and setting a non-default port before
  376. * getting to the protocol; we want that non-default port
  377. * to be preserved.
  378. */
  379. int port = conf_get_int(conf, CONF_port);
  380. if (port == cvt->default_port)
  381. conf_set_int(conf, CONF_port, nvt->default_port);
  382. dlg_refresh(hp->host, dlg);
  383. dlg_refresh(hp->port, dlg);
  384. }
  385. }
  386. }
  387. static void loggingbuttons_handler(dlgcontrol *ctrl, dlgparam *dlg,
  388. void *data, int event)
  389. {
  390. int button;
  391. Conf *conf = (Conf *)data;
  392. /* This function works just like the standard radio-button handler,
  393. * but it has to fall back to "no logging" in situations where the
  394. * configured logging type isn't applicable.
  395. */
  396. if (event == EVENT_REFRESH) {
  397. int logtype = conf_get_int(conf, CONF_logtype);
  398. for (button = 0; button < ctrl->radio.nbuttons; button++)
  399. if (logtype == ctrl->radio.buttondata[button].i)
  400. break;
  401. /* We fell off the end, so we lack the configured logging type */
  402. if (button == ctrl->radio.nbuttons) {
  403. button = 0;
  404. conf_set_int(conf, CONF_logtype, LGTYP_NONE);
  405. }
  406. dlg_radiobutton_set(ctrl, dlg, button);
  407. } else if (event == EVENT_VALCHANGE) {
  408. button = dlg_radiobutton_get(ctrl, dlg);
  409. assert(button >= 0 && button < ctrl->radio.nbuttons);
  410. conf_set_int(conf, CONF_logtype, ctrl->radio.buttondata[button].i);
  411. }
  412. }
  413. static void numeric_keypad_handler(dlgcontrol *ctrl, dlgparam *dlg,
  414. void *data, int event)
  415. {
  416. int button;
  417. Conf *conf = (Conf *)data;
  418. /*
  419. * This function works much like the standard radio button
  420. * handler, but it has to handle two fields in Conf.
  421. */
  422. if (event == EVENT_REFRESH) {
  423. if (conf_get_bool(conf, CONF_nethack_keypad))
  424. button = 2;
  425. else if (conf_get_bool(conf, CONF_app_keypad))
  426. button = 1;
  427. else
  428. button = 0;
  429. assert(button < ctrl->radio.nbuttons);
  430. dlg_radiobutton_set(ctrl, dlg, button);
  431. } else if (event == EVENT_VALCHANGE) {
  432. button = dlg_radiobutton_get(ctrl, dlg);
  433. assert(button >= 0 && button < ctrl->radio.nbuttons);
  434. if (button == 2) {
  435. conf_set_bool(conf, CONF_app_keypad, false);
  436. conf_set_bool(conf, CONF_nethack_keypad, true);
  437. } else {
  438. conf_set_bool(conf, CONF_app_keypad, (button != 0));
  439. conf_set_bool(conf, CONF_nethack_keypad, false);
  440. }
  441. }
  442. }
  443. static void cipherlist_handler(dlgcontrol *ctrl, dlgparam *dlg,
  444. void *data, int event)
  445. {
  446. Conf *conf = (Conf *)data;
  447. if (event == EVENT_REFRESH) {
  448. int i;
  449. static const struct { const char *s; int c; } ciphers[] = {
  450. { "ChaCha20 (SSH-2 only)", CIPHER_CHACHA20 },
  451. { "AES-GCM (SSH-2 only)", CIPHER_AESGCM },
  452. { "3DES", CIPHER_3DES },
  453. { "Blowfish", CIPHER_BLOWFISH },
  454. { "DES", CIPHER_DES },
  455. { "AES (SSH-2 only)", CIPHER_AES },
  456. { "Arcfour (SSH-2 only)", CIPHER_ARCFOUR },
  457. { "-- warn below here --", CIPHER_WARN }
  458. };
  459. /* Set up the "selected ciphers" box. */
  460. /* (cipherlist assumed to contain all ciphers) */
  461. dlg_update_start(ctrl, dlg);
  462. dlg_listbox_clear(ctrl, dlg);
  463. for (i = 0; i < CIPHER_MAX; i++) {
  464. int c = conf_get_int_int(conf, CONF_ssh_cipherlist, i);
  465. int j;
  466. const char *cstr = NULL;
  467. for (j = 0; j < (sizeof ciphers) / (sizeof ciphers[0]); j++) {
  468. if (ciphers[j].c == c) {
  469. cstr = ciphers[j].s;
  470. break;
  471. }
  472. }
  473. dlg_listbox_addwithid(ctrl, dlg, cstr, c);
  474. }
  475. dlg_update_done(ctrl, dlg);
  476. } else if (event == EVENT_VALCHANGE) {
  477. int i;
  478. /* Update array to match the list box. */
  479. for (i=0; i < CIPHER_MAX; i++)
  480. conf_set_int_int(conf, CONF_ssh_cipherlist, i,
  481. dlg_listbox_getid(ctrl, dlg, i));
  482. }
  483. }
  484. #ifndef NO_GSSAPI
  485. static void gsslist_handler(dlgcontrol *ctrl, dlgparam *dlg,
  486. void *data, int event)
  487. {
  488. Conf *conf = (Conf *)data;
  489. if (event == EVENT_REFRESH) {
  490. int i;
  491. dlg_update_start(ctrl, dlg);
  492. dlg_listbox_clear(ctrl, dlg);
  493. for (i = 0; i < ngsslibs; i++) {
  494. int id = conf_get_int_int(conf, CONF_ssh_gsslist, i);
  495. assert(id >= 0 && id < ngsslibs);
  496. dlg_listbox_addwithid(ctrl, dlg, gsslibnames[id], id);
  497. }
  498. dlg_update_done(ctrl, dlg);
  499. } else if (event == EVENT_VALCHANGE) {
  500. int i;
  501. /* Update array to match the list box. */
  502. for (i=0; i < ngsslibs; i++)
  503. conf_set_int_int(conf, CONF_ssh_gsslist, i,
  504. dlg_listbox_getid(ctrl, dlg, i));
  505. }
  506. }
  507. #endif
  508. static void kexlist_handler(dlgcontrol *ctrl, dlgparam *dlg,
  509. void *data, int event)
  510. {
  511. Conf *conf = (Conf *)data;
  512. if (event == EVENT_REFRESH) {
  513. int i;
  514. static const struct { const char *s; int k; } kexes[] = {
  515. { "Diffie-Hellman group 1 (1024-bit)", KEX_DHGROUP1 },
  516. { "Diffie-Hellman group 14 (2048-bit)", KEX_DHGROUP14 },
  517. { "Diffie-Hellman group 15 (3072-bit)", KEX_DHGROUP15 },
  518. { "Diffie-Hellman group 16 (4096-bit)", KEX_DHGROUP16 },
  519. { "Diffie-Hellman group 17 (6144-bit)", KEX_DHGROUP17 },
  520. { "Diffie-Hellman group 18 (8192-bit)", KEX_DHGROUP18 },
  521. { "Diffie-Hellman group exchange", KEX_DHGEX },
  522. { "RSA-based key exchange", KEX_RSA },
  523. { "ECDH key exchange", KEX_ECDH },
  524. { "NTRU Prime / Curve25519 hybrid kex", KEX_NTRU_HYBRID },
  525. { "-- warn below here --", KEX_WARN }
  526. };
  527. /* Set up the "kex preference" box. */
  528. /* (kexlist assumed to contain all algorithms) */
  529. dlg_update_start(ctrl, dlg);
  530. dlg_listbox_clear(ctrl, dlg);
  531. for (i = 0; i < KEX_MAX; i++) {
  532. int k = conf_get_int_int(conf, CONF_ssh_kexlist, i);
  533. int j;
  534. const char *kstr = NULL;
  535. for (j = 0; j < (sizeof kexes) / (sizeof kexes[0]); j++) {
  536. if (kexes[j].k == k) {
  537. kstr = kexes[j].s;
  538. break;
  539. }
  540. }
  541. dlg_listbox_addwithid(ctrl, dlg, kstr, k);
  542. }
  543. dlg_update_done(ctrl, dlg);
  544. } else if (event == EVENT_VALCHANGE) {
  545. int i;
  546. /* Update array to match the list box. */
  547. for (i=0; i < KEX_MAX; i++)
  548. conf_set_int_int(conf, CONF_ssh_kexlist, i,
  549. dlg_listbox_getid(ctrl, dlg, i));
  550. }
  551. }
  552. static void hklist_handler(dlgcontrol *ctrl, dlgparam *dlg,
  553. void *data, int event)
  554. {
  555. Conf *conf = (Conf *)data;
  556. if (event == EVENT_REFRESH) {
  557. int i;
  558. static const struct { const char *s; int k; } hks[] = {
  559. { "Ed25519", HK_ED25519 },
  560. { "Ed448", HK_ED448 },
  561. { "ECDSA", HK_ECDSA },
  562. { "DSA", HK_DSA },
  563. { "RSA", HK_RSA },
  564. { "-- warn below here --", HK_WARN }
  565. };
  566. /* Set up the "host key preference" box. */
  567. /* (hklist assumed to contain all algorithms) */
  568. dlg_update_start(ctrl, dlg);
  569. dlg_listbox_clear(ctrl, dlg);
  570. for (i = 0; i < HK_MAX; i++) {
  571. int k = conf_get_int_int(conf, CONF_ssh_hklist, i);
  572. int j;
  573. const char *kstr = NULL;
  574. for (j = 0; j < lenof(hks); j++) {
  575. if (hks[j].k == k) {
  576. kstr = hks[j].s;
  577. break;
  578. }
  579. }
  580. dlg_listbox_addwithid(ctrl, dlg, kstr, k);
  581. }
  582. dlg_update_done(ctrl, dlg);
  583. } else if (event == EVENT_VALCHANGE) {
  584. int i;
  585. /* Update array to match the list box. */
  586. for (i=0; i < HK_MAX; i++)
  587. conf_set_int_int(conf, CONF_ssh_hklist, i,
  588. dlg_listbox_getid(ctrl, dlg, i));
  589. }
  590. }
  591. static void printerbox_handler(dlgcontrol *ctrl, dlgparam *dlg,
  592. void *data, int event)
  593. {
  594. Conf *conf = (Conf *)data;
  595. if (event == EVENT_REFRESH) {
  596. int nprinters, i;
  597. printer_enum *pe;
  598. const char *printer;
  599. dlg_update_start(ctrl, dlg);
  600. /*
  601. * Some backends may wish to disable the drop-down list on
  602. * this edit box. Be prepared for this.
  603. */
  604. if (ctrl->editbox.has_list) {
  605. dlg_listbox_clear(ctrl, dlg);
  606. dlg_listbox_add(ctrl, dlg, PRINTER_DISABLED_STRING);
  607. pe = printer_start_enum(&nprinters);
  608. for (i = 0; i < nprinters; i++)
  609. dlg_listbox_add(ctrl, dlg, printer_get_name(pe, i));
  610. printer_finish_enum(pe);
  611. }
  612. printer = conf_get_str(conf, CONF_printer);
  613. if (!printer)
  614. printer = PRINTER_DISABLED_STRING;
  615. dlg_editbox_set(ctrl, dlg, printer);
  616. dlg_update_done(ctrl, dlg);
  617. } else if (event == EVENT_VALCHANGE) {
  618. char *printer = dlg_editbox_get(ctrl, dlg);
  619. if (!strcmp(printer, PRINTER_DISABLED_STRING))
  620. printer[0] = '\0';
  621. conf_set_str(conf, CONF_printer, printer);
  622. sfree(printer);
  623. }
  624. }
  625. static void codepage_handler(dlgcontrol *ctrl, dlgparam *dlg,
  626. void *data, int event)
  627. {
  628. Conf *conf = (Conf *)data;
  629. if (event == EVENT_REFRESH) {
  630. int i;
  631. const char *cp, *thiscp;
  632. dlg_update_start(ctrl, dlg);
  633. thiscp = cp_name(decode_codepage(conf_get_str(conf,
  634. CONF_line_codepage)));
  635. dlg_listbox_clear(ctrl, dlg);
  636. for (i = 0; (cp = cp_enumerate(i)) != NULL; i++)
  637. dlg_listbox_add(ctrl, dlg, cp);
  638. dlg_editbox_set(ctrl, dlg, thiscp);
  639. conf_set_str(conf, CONF_line_codepage, thiscp);
  640. dlg_update_done(ctrl, dlg);
  641. } else if (event == EVENT_VALCHANGE) {
  642. char *codepage = dlg_editbox_get(ctrl, dlg);
  643. conf_set_str(conf, CONF_line_codepage,
  644. cp_name(decode_codepage(codepage)));
  645. sfree(codepage);
  646. }
  647. }
  648. static void sshbug_handler(dlgcontrol *ctrl, dlgparam *dlg,
  649. void *data, int event)
  650. {
  651. Conf *conf = (Conf *)data;
  652. if (event == EVENT_REFRESH) {
  653. /*
  654. * We must fetch the previously configured value from the Conf
  655. * before we start modifying the drop-down list, otherwise the
  656. * spurious SELCHANGE we trigger in the process will overwrite
  657. * the value we wanted to keep.
  658. */
  659. int oldconf = conf_get_int(conf, ctrl->context.i);
  660. dlg_update_start(ctrl, dlg);
  661. dlg_listbox_clear(ctrl, dlg);
  662. dlg_listbox_addwithid(ctrl, dlg, "Auto", AUTO);
  663. dlg_listbox_addwithid(ctrl, dlg, "Off", FORCE_OFF);
  664. dlg_listbox_addwithid(ctrl, dlg, "On", FORCE_ON);
  665. switch (oldconf) {
  666. case AUTO: dlg_listbox_select(ctrl, dlg, 0); break;
  667. case FORCE_OFF: dlg_listbox_select(ctrl, dlg, 1); break;
  668. case FORCE_ON: dlg_listbox_select(ctrl, dlg, 2); break;
  669. }
  670. dlg_update_done(ctrl, dlg);
  671. } else if (event == EVENT_SELCHANGE) {
  672. int i = dlg_listbox_index(ctrl, dlg);
  673. if (i < 0)
  674. i = AUTO;
  675. else
  676. i = dlg_listbox_getid(ctrl, dlg, i);
  677. conf_set_int(conf, ctrl->context.i, i);
  678. }
  679. }
  680. static void sshbug_handler_manual_only(dlgcontrol *ctrl, dlgparam *dlg,
  681. void *data, int event)
  682. {
  683. /*
  684. * This is just like sshbug_handler, except that there's no 'Auto'
  685. * option. Used for bug workaround flags that can't be
  686. * autodetected, and have to be manually enabled if they're to be
  687. * used at all.
  688. */
  689. Conf *conf = (Conf *)data;
  690. if (event == EVENT_REFRESH) {
  691. int oldconf = conf_get_int(conf, ctrl->context.i);
  692. dlg_update_start(ctrl, dlg);
  693. dlg_listbox_clear(ctrl, dlg);
  694. dlg_listbox_addwithid(ctrl, dlg, "Off", FORCE_OFF);
  695. dlg_listbox_addwithid(ctrl, dlg, "On", FORCE_ON);
  696. switch (oldconf) {
  697. case FORCE_OFF: dlg_listbox_select(ctrl, dlg, 0); break;
  698. case FORCE_ON: dlg_listbox_select(ctrl, dlg, 1); break;
  699. }
  700. dlg_update_done(ctrl, dlg);
  701. } else if (event == EVENT_SELCHANGE) {
  702. int i = dlg_listbox_index(ctrl, dlg);
  703. if (i < 0)
  704. i = FORCE_OFF;
  705. else
  706. i = dlg_listbox_getid(ctrl, dlg, i);
  707. conf_set_int(conf, ctrl->context.i, i);
  708. }
  709. }
  710. struct sessionsaver_data {
  711. dlgcontrol *editbox, *listbox, *loadbutton, *savebutton, *delbutton;
  712. dlgcontrol *okbutton, *cancelbutton;
  713. struct sesslist sesslist;
  714. bool midsession;
  715. char *savedsession; /* the current contents of ssd->editbox */
  716. };
  717. static void sessionsaver_data_free(void *ssdv)
  718. {
  719. struct sessionsaver_data *ssd = (struct sessionsaver_data *)ssdv;
  720. get_sesslist(&ssd->sesslist, false);
  721. sfree(ssd->savedsession);
  722. sfree(ssd);
  723. }
  724. /*
  725. * Helper function to load the session selected in the list box, if
  726. * any, as this is done in more than one place below. Returns 0 for
  727. * failure.
  728. */
  729. static bool load_selected_session(
  730. struct sessionsaver_data *ssd,
  731. dlgparam *dlg, Conf *conf, bool *maybe_launch)
  732. {
  733. int i = dlg_listbox_index(ssd->listbox, dlg);
  734. bool isdef;
  735. if (i < 0) {
  736. dlg_beep(dlg);
  737. return false;
  738. }
  739. isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings");
  740. load_settings(ssd->sesslist.sessions[i], conf);
  741. sfree(ssd->savedsession);
  742. ssd->savedsession = dupstr(isdef ? "" : ssd->sesslist.sessions[i]);
  743. if (maybe_launch)
  744. *maybe_launch = !isdef;
  745. dlg_refresh(NULL, dlg);
  746. /* Restore the selection, which might have been clobbered by
  747. * changing the value of the edit box. */
  748. dlg_listbox_select(ssd->listbox, dlg, i);
  749. return true;
  750. }
  751. static void sessionsaver_handler(dlgcontrol *ctrl, dlgparam *dlg,
  752. void *data, int event)
  753. {
  754. Conf *conf = (Conf *)data;
  755. struct sessionsaver_data *ssd =
  756. (struct sessionsaver_data *)ctrl->context.p;
  757. if (event == EVENT_REFRESH) {
  758. if (ctrl == ssd->editbox) {
  759. dlg_editbox_set(ctrl, dlg, ssd->savedsession);
  760. } else if (ctrl == ssd->listbox) {
  761. int i;
  762. dlg_update_start(ctrl, dlg);
  763. dlg_listbox_clear(ctrl, dlg);
  764. for (i = 0; i < ssd->sesslist.nsessions; i++)
  765. dlg_listbox_add(ctrl, dlg, ssd->sesslist.sessions[i]);
  766. dlg_update_done(ctrl, dlg);
  767. }
  768. } else if (event == EVENT_VALCHANGE) {
  769. int top, bottom, halfway, i;
  770. if (ctrl == ssd->editbox) {
  771. sfree(ssd->savedsession);
  772. ssd->savedsession = dlg_editbox_get(ctrl, dlg);
  773. top = ssd->sesslist.nsessions;
  774. bottom = -1;
  775. while (top-bottom > 1) {
  776. halfway = (top+bottom)/2;
  777. i = strcmp(ssd->savedsession, ssd->sesslist.sessions[halfway]);
  778. if (i <= 0 ) {
  779. top = halfway;
  780. } else {
  781. bottom = halfway;
  782. }
  783. }
  784. if (top == ssd->sesslist.nsessions) {
  785. top -= 1;
  786. }
  787. dlg_listbox_select(ssd->listbox, dlg, top);
  788. }
  789. } else if (event == EVENT_ACTION) {
  790. bool mbl = false;
  791. if (!ssd->midsession &&
  792. (ctrl == ssd->listbox ||
  793. (ssd->loadbutton && ctrl == ssd->loadbutton))) {
  794. /*
  795. * The user has double-clicked a session, or hit Load.
  796. * We must load the selected session, and then
  797. * terminate the configuration dialog _if_ there was a
  798. * double-click on the list box _and_ that session
  799. * contains a hostname.
  800. */
  801. if (load_selected_session(ssd, dlg, conf, &mbl) &&
  802. (mbl && ctrl == ssd->listbox && conf_launchable(conf))) {
  803. dlg_end(dlg, 1); /* it's all over, and succeeded */
  804. }
  805. } else if (ctrl == ssd->savebutton) {
  806. bool isdef = !strcmp(ssd->savedsession, "Default Settings");
  807. if (!ssd->savedsession[0]) {
  808. int i = dlg_listbox_index(ssd->listbox, dlg);
  809. if (i < 0) {
  810. dlg_beep(dlg);
  811. return;
  812. }
  813. isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings");
  814. sfree(ssd->savedsession);
  815. ssd->savedsession = dupstr(isdef ? "" :
  816. ssd->sesslist.sessions[i]);
  817. }
  818. {
  819. char *errmsg = save_settings(ssd->savedsession, conf);
  820. if (errmsg) {
  821. dlg_error_msg(dlg, errmsg);
  822. sfree(errmsg);
  823. }
  824. }
  825. get_sesslist(&ssd->sesslist, false);
  826. get_sesslist(&ssd->sesslist, true);
  827. dlg_refresh(ssd->editbox, dlg);
  828. dlg_refresh(ssd->listbox, dlg);
  829. } else if (!ssd->midsession &&
  830. ssd->delbutton && ctrl == ssd->delbutton) {
  831. int i = dlg_listbox_index(ssd->listbox, dlg);
  832. if (i <= 0) {
  833. dlg_beep(dlg);
  834. } else {
  835. del_settings(ssd->sesslist.sessions[i]);
  836. get_sesslist(&ssd->sesslist, false);
  837. get_sesslist(&ssd->sesslist, true);
  838. dlg_refresh(ssd->listbox, dlg);
  839. }
  840. } else if (ctrl == ssd->okbutton) {
  841. if (ssd->midsession) {
  842. /* In a mid-session Change Settings, Apply is always OK. */
  843. dlg_end(dlg, 1);
  844. return;
  845. }
  846. /*
  847. * Annoying special case. If the `Open' button is
  848. * pressed while no host name is currently set, _and_
  849. * the session list previously had the focus, _and_
  850. * there was a session selected in that which had a
  851. * valid host name in it, then load it and go.
  852. */
  853. if (dlg_last_focused(ctrl, dlg) == ssd->listbox &&
  854. !conf_launchable(conf) && dlg_is_visible(ssd->listbox, dlg)) {
  855. Conf *conf2 = conf_new();
  856. bool mbl = false;
  857. if (!load_selected_session(ssd, dlg, conf2, &mbl)) {
  858. dlg_beep(dlg);
  859. conf_free(conf2);
  860. return;
  861. }
  862. /* If at this point we have a valid session, go! */
  863. if (mbl && conf_launchable(conf2)) {
  864. conf_copy_into(conf, conf2);
  865. dlg_end(dlg, 1);
  866. } else
  867. dlg_beep(dlg);
  868. conf_free(conf2);
  869. return;
  870. }
  871. /*
  872. * Otherwise, do the normal thing: if we have a valid
  873. * session, get going.
  874. */
  875. if (conf_launchable(conf)) {
  876. dlg_end(dlg, 1);
  877. } else
  878. dlg_beep(dlg);
  879. } else if (ctrl == ssd->cancelbutton) {
  880. dlg_end(dlg, 0);
  881. }
  882. }
  883. }
  884. struct charclass_data {
  885. dlgcontrol *listbox, *editbox, *button;
  886. };
  887. static void charclass_handler(dlgcontrol *ctrl, dlgparam *dlg,
  888. void *data, int event)
  889. {
  890. Conf *conf = (Conf *)data;
  891. struct charclass_data *ccd =
  892. (struct charclass_data *)ctrl->context.p;
  893. if (event == EVENT_REFRESH) {
  894. if (ctrl == ccd->listbox) {
  895. int i;
  896. dlg_update_start(ctrl, dlg);
  897. dlg_listbox_clear(ctrl, dlg);
  898. for (i = 0; i < 128; i++) {
  899. char str[100];
  900. sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
  901. (i >= 0x21 && i != 0x7F) ? i : ' ',
  902. conf_get_int_int(conf, CONF_wordness, i));
  903. dlg_listbox_add(ctrl, dlg, str);
  904. }
  905. dlg_update_done(ctrl, dlg);
  906. }
  907. } else if (event == EVENT_ACTION) {
  908. if (ctrl == ccd->button) {
  909. char *str;
  910. int i, n;
  911. str = dlg_editbox_get(ccd->editbox, dlg);
  912. n = atoi(str);
  913. sfree(str);
  914. for (i = 0; i < 128; i++) {
  915. if (dlg_listbox_issel(ccd->listbox, dlg, i))
  916. conf_set_int_int(conf, CONF_wordness, i, n);
  917. }
  918. dlg_refresh(ccd->listbox, dlg);
  919. }
  920. }
  921. }
  922. struct colour_data {
  923. dlgcontrol *listbox, *redit, *gedit, *bedit, *button;
  924. };
  925. /* Array of the user-visible colour names defined in the list macro in
  926. * putty.h */
  927. static const char *const colours[] = {
  928. #define CONF_COLOUR_NAME_DECL(id,name) name,
  929. CONF_COLOUR_LIST(CONF_COLOUR_NAME_DECL)
  930. #undef CONF_COLOUR_NAME_DECL
  931. };
  932. static void colour_handler(dlgcontrol *ctrl, dlgparam *dlg,
  933. void *data, int event)
  934. {
  935. Conf *conf = (Conf *)data;
  936. struct colour_data *cd =
  937. (struct colour_data *)ctrl->context.p;
  938. bool update = false, clear = false;
  939. int r, g, b;
  940. if (event == EVENT_REFRESH) {
  941. if (ctrl == cd->listbox) {
  942. int i;
  943. dlg_update_start(ctrl, dlg);
  944. dlg_listbox_clear(ctrl, dlg);
  945. for (i = 0; i < lenof(colours); i++)
  946. dlg_listbox_add(ctrl, dlg, colours[i]);
  947. dlg_update_done(ctrl, dlg);
  948. clear = true;
  949. update = true;
  950. }
  951. } else if (event == EVENT_SELCHANGE) {
  952. if (ctrl == cd->listbox) {
  953. /* The user has selected a colour. Update the RGB text. */
  954. int i = dlg_listbox_index(ctrl, dlg);
  955. if (i < 0) {
  956. clear = true;
  957. } else {
  958. clear = false;
  959. r = conf_get_int_int(conf, CONF_colours, i*3+0);
  960. g = conf_get_int_int(conf, CONF_colours, i*3+1);
  961. b = conf_get_int_int(conf, CONF_colours, i*3+2);
  962. }
  963. update = true;
  964. }
  965. } else if (event == EVENT_VALCHANGE) {
  966. if (ctrl == cd->redit || ctrl == cd->gedit || ctrl == cd->bedit) {
  967. /* The user has changed the colour using the edit boxes. */
  968. char *str;
  969. int i, cval;
  970. str = dlg_editbox_get(ctrl, dlg);
  971. cval = atoi(str);
  972. sfree(str);
  973. if (cval > 255) cval = 255;
  974. if (cval < 0) cval = 0;
  975. i = dlg_listbox_index(cd->listbox, dlg);
  976. if (i >= 0) {
  977. if (ctrl == cd->redit)
  978. conf_set_int_int(conf, CONF_colours, i*3+0, cval);
  979. else if (ctrl == cd->gedit)
  980. conf_set_int_int(conf, CONF_colours, i*3+1, cval);
  981. else if (ctrl == cd->bedit)
  982. conf_set_int_int(conf, CONF_colours, i*3+2, cval);
  983. }
  984. }
  985. } else if (event == EVENT_ACTION) {
  986. if (ctrl == cd->button) {
  987. int i = dlg_listbox_index(cd->listbox, dlg);
  988. if (i < 0) {
  989. dlg_beep(dlg);
  990. return;
  991. }
  992. /*
  993. * Start a colour selector, which will send us an
  994. * EVENT_CALLBACK when it's finished and allow us to
  995. * pick up the results.
  996. */
  997. dlg_coloursel_start(ctrl, dlg,
  998. conf_get_int_int(conf, CONF_colours, i*3+0),
  999. conf_get_int_int(conf, CONF_colours, i*3+1),
  1000. conf_get_int_int(conf, CONF_colours, i*3+2));
  1001. }
  1002. } else if (event == EVENT_CALLBACK) {
  1003. if (ctrl == cd->button) {
  1004. int i = dlg_listbox_index(cd->listbox, dlg);
  1005. /*
  1006. * Collect the results of the colour selector. Will
  1007. * return nonzero on success, or zero if the colour
  1008. * selector did nothing (user hit Cancel, for example).
  1009. */
  1010. if (dlg_coloursel_results(ctrl, dlg, &r, &g, &b)) {
  1011. conf_set_int_int(conf, CONF_colours, i*3+0, r);
  1012. conf_set_int_int(conf, CONF_colours, i*3+1, g);
  1013. conf_set_int_int(conf, CONF_colours, i*3+2, b);
  1014. clear = false;
  1015. update = true;
  1016. }
  1017. }
  1018. }
  1019. if (update) {
  1020. if (clear) {
  1021. dlg_editbox_set(cd->redit, dlg, "");
  1022. dlg_editbox_set(cd->gedit, dlg, "");
  1023. dlg_editbox_set(cd->bedit, dlg, "");
  1024. } else {
  1025. char buf[40];
  1026. sprintf(buf, "%d", r); dlg_editbox_set(cd->redit, dlg, buf);
  1027. sprintf(buf, "%d", g); dlg_editbox_set(cd->gedit, dlg, buf);
  1028. sprintf(buf, "%d", b); dlg_editbox_set(cd->bedit, dlg, buf);
  1029. }
  1030. }
  1031. }
  1032. struct ttymodes_data {
  1033. dlgcontrol *valradio, *valbox, *setbutton, *listbox;
  1034. };
  1035. static void ttymodes_handler(dlgcontrol *ctrl, dlgparam *dlg,
  1036. void *data, int event)
  1037. {
  1038. Conf *conf = (Conf *)data;
  1039. struct ttymodes_data *td =
  1040. (struct ttymodes_data *)ctrl->context.p;
  1041. if (event == EVENT_REFRESH) {
  1042. if (ctrl == td->listbox) {
  1043. char *key, *val;
  1044. dlg_update_start(ctrl, dlg);
  1045. dlg_listbox_clear(ctrl, dlg);
  1046. for (val = conf_get_str_strs(conf, CONF_ttymodes, NULL, &key);
  1047. val != NULL;
  1048. val = conf_get_str_strs(conf, CONF_ttymodes, key, &key)) {
  1049. char *disp = dupprintf("%s\t%s", key,
  1050. (val[0] == 'A') ? "(auto)" :
  1051. ((val[0] == 'N') ? "(don't send)"
  1052. : val+1));
  1053. dlg_listbox_add(ctrl, dlg, disp);
  1054. sfree(disp);
  1055. }
  1056. dlg_update_done(ctrl, dlg);
  1057. } else if (ctrl == td->valradio) {
  1058. dlg_radiobutton_set(ctrl, dlg, 0);
  1059. }
  1060. } else if (event == EVENT_SELCHANGE) {
  1061. if (ctrl == td->listbox) {
  1062. int ind = dlg_listbox_index(td->listbox, dlg);
  1063. char *val;
  1064. if (ind < 0) {
  1065. return; /* no item selected */
  1066. }
  1067. val = conf_get_str_str(conf, CONF_ttymodes,
  1068. conf_get_str_nthstrkey(conf, CONF_ttymodes,
  1069. ind));
  1070. assert(val != NULL);
  1071. /* Do this first to defuse side-effects on radio buttons: */
  1072. dlg_editbox_set(td->valbox, dlg, val+1);
  1073. dlg_radiobutton_set(td->valradio, dlg,
  1074. val[0] == 'A' ? 0 : (val[0] == 'N' ? 1 : 2));
  1075. }
  1076. } else if (event == EVENT_VALCHANGE) {
  1077. if (ctrl == td->valbox) {
  1078. /* If they're editing the text box, we assume they want its
  1079. * value to be used. */
  1080. dlg_radiobutton_set(td->valradio, dlg, 2);
  1081. }
  1082. } else if (event == EVENT_ACTION) {
  1083. if (ctrl == td->setbutton) {
  1084. int ind = dlg_listbox_index(td->listbox, dlg);
  1085. const char *key;
  1086. char *str, *val;
  1087. char type;
  1088. {
  1089. const char types[] = {'A', 'N', 'V'};
  1090. int button = dlg_radiobutton_get(td->valradio, dlg);
  1091. assert(button >= 0 && button < lenof(types));
  1092. type = types[button];
  1093. }
  1094. /* Construct new entry */
  1095. if (ind >= 0) {
  1096. key = conf_get_str_nthstrkey(conf, CONF_ttymodes, ind);
  1097. str = (type == 'V' ? dlg_editbox_get(td->valbox, dlg)
  1098. : dupstr(""));
  1099. val = dupprintf("%c%s", type, str);
  1100. sfree(str);
  1101. conf_set_str_str(conf, CONF_ttymodes, key, val);
  1102. sfree(val);
  1103. dlg_refresh(td->listbox, dlg);
  1104. dlg_listbox_select(td->listbox, dlg, ind);
  1105. } else {
  1106. /* Not a multisel listbox, so this means nothing selected */
  1107. dlg_beep(dlg);
  1108. }
  1109. }
  1110. }
  1111. }
  1112. struct environ_data {
  1113. dlgcontrol *varbox, *valbox, *addbutton, *rembutton, *listbox;
  1114. };
  1115. static void environ_handler(dlgcontrol *ctrl, dlgparam *dlg,
  1116. void *data, int event)
  1117. {
  1118. Conf *conf = (Conf *)data;
  1119. struct environ_data *ed =
  1120. (struct environ_data *)ctrl->context.p;
  1121. if (event == EVENT_REFRESH) {
  1122. if (ctrl == ed->listbox) {
  1123. char *key, *val;
  1124. dlg_update_start(ctrl, dlg);
  1125. dlg_listbox_clear(ctrl, dlg);
  1126. for (val = conf_get_str_strs(conf, CONF_environmt, NULL, &key);
  1127. val != NULL;
  1128. val = conf_get_str_strs(conf, CONF_environmt, key, &key)) {
  1129. char *p = dupprintf("%s\t%s", key, val);
  1130. dlg_listbox_add(ctrl, dlg, p);
  1131. sfree(p);
  1132. }
  1133. dlg_update_done(ctrl, dlg);
  1134. }
  1135. } else if (event == EVENT_ACTION) {
  1136. if (ctrl == ed->addbutton) {
  1137. char *key, *val, *str;
  1138. key = dlg_editbox_get(ed->varbox, dlg);
  1139. if (!*key) {
  1140. sfree(key);
  1141. dlg_beep(dlg);
  1142. return;
  1143. }
  1144. val = dlg_editbox_get(ed->valbox, dlg);
  1145. if (!*val) {
  1146. sfree(key);
  1147. sfree(val);
  1148. dlg_beep(dlg);
  1149. return;
  1150. }
  1151. conf_set_str_str(conf, CONF_environmt, key, val);
  1152. str = dupcat(key, "\t", val);
  1153. dlg_editbox_set(ed->varbox, dlg, "");
  1154. dlg_editbox_set(ed->valbox, dlg, "");
  1155. sfree(str);
  1156. sfree(key);
  1157. sfree(val);
  1158. dlg_refresh(ed->listbox, dlg);
  1159. } else if (ctrl == ed->rembutton) {
  1160. int i = dlg_listbox_index(ed->listbox, dlg);
  1161. if (i < 0) {
  1162. dlg_beep(dlg);
  1163. } else {
  1164. char *key, *val;
  1165. key = conf_get_str_nthstrkey(conf, CONF_environmt, i);
  1166. if (key) {
  1167. /* Populate controls with the entry we're about to delete
  1168. * for ease of editing */
  1169. val = conf_get_str_str(conf, CONF_environmt, key);
  1170. dlg_editbox_set(ed->varbox, dlg, key);
  1171. dlg_editbox_set(ed->valbox, dlg, val);
  1172. /* And delete it */
  1173. conf_del_str_str(conf, CONF_environmt, key);
  1174. }
  1175. }
  1176. dlg_refresh(ed->listbox, dlg);
  1177. }
  1178. }
  1179. }
  1180. struct portfwd_data {
  1181. dlgcontrol *addbutton, *rembutton, *listbox;
  1182. dlgcontrol *sourcebox, *destbox, *direction;
  1183. #ifndef NO_IPV6
  1184. dlgcontrol *addressfamily;
  1185. #endif
  1186. };
  1187. static void portfwd_handler(dlgcontrol *ctrl, dlgparam *dlg,
  1188. void *data, int event)
  1189. {
  1190. Conf *conf = (Conf *)data;
  1191. struct portfwd_data *pfd =
  1192. (struct portfwd_data *)ctrl->context.p;
  1193. if (event == EVENT_REFRESH) {
  1194. if (ctrl == pfd->listbox) {
  1195. char *key, *val;
  1196. dlg_update_start(ctrl, dlg);
  1197. dlg_listbox_clear(ctrl, dlg);
  1198. for (val = conf_get_str_strs(conf, CONF_portfwd, NULL, &key);
  1199. val != NULL;
  1200. val = conf_get_str_strs(conf, CONF_portfwd, key, &key)) {
  1201. char *p;
  1202. if (!strcmp(val, "D")) {
  1203. char *L;
  1204. /*
  1205. * A dynamic forwarding is stored as L12345=D or
  1206. * 6L12345=D (since it's mutually exclusive with
  1207. * L12345=anything else), but displayed as D12345
  1208. * to match the fiction that 'Local', 'Remote' and
  1209. * 'Dynamic' are three distinct modes and also to
  1210. * align with OpenSSH's command line option syntax
  1211. * that people will already be used to. So, for
  1212. * display purposes, find the L in the key string
  1213. * and turn it into a D.
  1214. */
  1215. p = dupprintf("%s\t", key);
  1216. L = strchr(p, 'L');
  1217. if (L) *L = 'D';
  1218. } else
  1219. p = dupprintf("%s\t%s", key, val);
  1220. dlg_listbox_add(ctrl, dlg, p);
  1221. sfree(p);
  1222. }
  1223. dlg_update_done(ctrl, dlg);
  1224. } else if (ctrl == pfd->direction) {
  1225. /*
  1226. * Default is Local.
  1227. */
  1228. dlg_radiobutton_set(ctrl, dlg, 0);
  1229. #ifndef NO_IPV6
  1230. } else if (ctrl == pfd->addressfamily) {
  1231. dlg_radiobutton_set(ctrl, dlg, 0);
  1232. #endif
  1233. }
  1234. } else if (event == EVENT_ACTION) {
  1235. if (ctrl == pfd->addbutton) {
  1236. const char *family, *type;
  1237. char *src, *key, *val;
  1238. int whichbutton;
  1239. #ifndef NO_IPV6
  1240. whichbutton = dlg_radiobutton_get(pfd->addressfamily, dlg);
  1241. if (whichbutton == 1)
  1242. family = "4";
  1243. else if (whichbutton == 2)
  1244. family = "6";
  1245. else
  1246. #endif
  1247. family = "";
  1248. whichbutton = dlg_radiobutton_get(pfd->direction, dlg);
  1249. if (whichbutton == 0)
  1250. type = "L";
  1251. else if (whichbutton == 1)
  1252. type = "R";
  1253. else
  1254. type = "D";
  1255. src = dlg_editbox_get(pfd->sourcebox, dlg);
  1256. if (!*src) {
  1257. dlg_error_msg(dlg, "You need to specify a source port number");
  1258. sfree(src);
  1259. return;
  1260. }
  1261. if (*type != 'D') {
  1262. val = dlg_editbox_get(pfd->destbox, dlg);
  1263. if (!*val || !host_strchr(val, ':')) {
  1264. dlg_error_msg(dlg,
  1265. "You need to specify a destination address\n"
  1266. "in the form \"host.name:port\"");
  1267. sfree(src);
  1268. sfree(val);
  1269. return;
  1270. }
  1271. } else {
  1272. type = "L";
  1273. val = dupstr("D"); /* special case */
  1274. }
  1275. key = dupcat(family, type, src);
  1276. sfree(src);
  1277. if (conf_get_str_str_opt(conf, CONF_portfwd, key)) {
  1278. dlg_error_msg(dlg, "Specified forwarding already exists");
  1279. } else {
  1280. conf_set_str_str(conf, CONF_portfwd, key, val);
  1281. }
  1282. sfree(key);
  1283. sfree(val);
  1284. dlg_refresh(pfd->listbox, dlg);
  1285. } else if (ctrl == pfd->rembutton) {
  1286. int i = dlg_listbox_index(pfd->listbox, dlg);
  1287. if (i < 0) {
  1288. dlg_beep(dlg);
  1289. } else {
  1290. char *key, *p;
  1291. const char *val;
  1292. key = conf_get_str_nthstrkey(conf, CONF_portfwd, i);
  1293. if (key) {
  1294. static const char *const afs = "A46";
  1295. static const char *const dirs = "LRD";
  1296. const char *afp;
  1297. int dir;
  1298. #ifndef NO_IPV6
  1299. int idx;
  1300. #endif
  1301. /* Populate controls with the entry we're about to delete
  1302. * for ease of editing */
  1303. p = key;
  1304. afp = strchr(afs, *p);
  1305. #ifndef NO_IPV6
  1306. idx = afp ? afp-afs : 0;
  1307. #endif
  1308. if (afp)
  1309. p++;
  1310. #ifndef NO_IPV6
  1311. dlg_radiobutton_set(pfd->addressfamily, dlg, idx);
  1312. #endif
  1313. dir = *p;
  1314. val = conf_get_str_str(conf, CONF_portfwd, key);
  1315. if (!strcmp(val, "D")) {
  1316. dir = 'D';
  1317. val = "";
  1318. }
  1319. dlg_radiobutton_set(pfd->direction, dlg,
  1320. strchr(dirs, dir) - dirs);
  1321. p++;
  1322. dlg_editbox_set(pfd->sourcebox, dlg, p);
  1323. dlg_editbox_set(pfd->destbox, dlg, val);
  1324. /* And delete it */
  1325. conf_del_str_str(conf, CONF_portfwd, key);
  1326. }
  1327. }
  1328. dlg_refresh(pfd->listbox, dlg);
  1329. }
  1330. }
  1331. }
  1332. struct manual_hostkey_data {
  1333. dlgcontrol *addbutton, *rembutton, *listbox, *keybox;
  1334. };
  1335. static void manual_hostkey_handler(dlgcontrol *ctrl, dlgparam *dlg,
  1336. void *data, int event)
  1337. {
  1338. Conf *conf = (Conf *)data;
  1339. struct manual_hostkey_data *mh =
  1340. (struct manual_hostkey_data *)ctrl->context.p;
  1341. if (event == EVENT_REFRESH) {
  1342. if (ctrl == mh->listbox) {
  1343. char *key, *val;
  1344. dlg_update_start(ctrl, dlg);
  1345. dlg_listbox_clear(ctrl, dlg);
  1346. for (val = conf_get_str_strs(conf, CONF_ssh_manual_hostkeys,
  1347. NULL, &key);
  1348. val != NULL;
  1349. val = conf_get_str_strs(conf, CONF_ssh_manual_hostkeys,
  1350. key, &key)) {
  1351. dlg_listbox_add(ctrl, dlg, key);
  1352. }
  1353. dlg_update_done(ctrl, dlg);
  1354. }
  1355. } else if (event == EVENT_ACTION) {
  1356. if (ctrl == mh->addbutton) {
  1357. char *key;
  1358. key = dlg_editbox_get(mh->keybox, dlg);
  1359. if (!*key) {
  1360. dlg_error_msg(dlg, "You need to specify a host key or "
  1361. "fingerprint");
  1362. sfree(key);
  1363. return;
  1364. }
  1365. if (!validate_manual_hostkey(key)) {
  1366. dlg_error_msg(dlg, "Host key is not in a valid format");
  1367. } else if (conf_get_str_str_opt(conf, CONF_ssh_manual_hostkeys,
  1368. key)) {
  1369. dlg_error_msg(dlg, "Specified host key is already listed");
  1370. } else {
  1371. conf_set_str_str(conf, CONF_ssh_manual_hostkeys, key, "");
  1372. }
  1373. sfree(key);
  1374. dlg_refresh(mh->listbox, dlg);
  1375. } else if (ctrl == mh->rembutton) {
  1376. int i = dlg_listbox_index(mh->listbox, dlg);
  1377. if (i < 0) {
  1378. dlg_beep(dlg);
  1379. } else {
  1380. char *key;
  1381. key = conf_get_str_nthstrkey(conf, CONF_ssh_manual_hostkeys, i);
  1382. if (key) {
  1383. dlg_editbox_set(mh->keybox, dlg, key);
  1384. /* And delete it */
  1385. conf_del_str_str(conf, CONF_ssh_manual_hostkeys, key);
  1386. }
  1387. }
  1388. dlg_refresh(mh->listbox, dlg);
  1389. }
  1390. }
  1391. }
  1392. static void clipboard_selector_handler(dlgcontrol *ctrl, dlgparam *dlg,
  1393. void *data, int event)
  1394. {
  1395. Conf *conf = (Conf *)data;
  1396. int setting = ctrl->context.i;
  1397. #ifdef NAMED_CLIPBOARDS
  1398. int strsetting = ctrl->context2.i;
  1399. #endif
  1400. static const struct {
  1401. const char *name;
  1402. int id;
  1403. } options[] = {
  1404. {"No action", CLIPUI_NONE},
  1405. {CLIPNAME_IMPLICIT, CLIPUI_IMPLICIT},
  1406. {CLIPNAME_EXPLICIT, CLIPUI_EXPLICIT},
  1407. };
  1408. if (event == EVENT_REFRESH) {
  1409. int i, val = conf_get_int(conf, setting);
  1410. dlg_update_start(ctrl, dlg);
  1411. dlg_listbox_clear(ctrl, dlg);
  1412. #ifdef NAMED_CLIPBOARDS
  1413. for (i = 0; i < lenof(options); i++)
  1414. dlg_listbox_add(ctrl, dlg, options[i].name);
  1415. if (val == CLIPUI_CUSTOM) {
  1416. const char *sval = conf_get_str(conf, strsetting);
  1417. for (i = 0; i < lenof(options); i++)
  1418. if (!strcmp(sval, options[i].name))
  1419. break; /* needs escaping */
  1420. if (i < lenof(options) || sval[0] == '=') {
  1421. char *escaped = dupcat("=", sval);
  1422. dlg_editbox_set(ctrl, dlg, escaped);
  1423. sfree(escaped);
  1424. } else {
  1425. dlg_editbox_set(ctrl, dlg, sval);
  1426. }
  1427. } else {
  1428. dlg_editbox_set(ctrl, dlg, options[0].name); /* fallback */
  1429. for (i = 0; i < lenof(options); i++)
  1430. if (val == options[i].id)
  1431. dlg_editbox_set(ctrl, dlg, options[i].name);
  1432. }
  1433. #else
  1434. for (i = 0; i < lenof(options); i++)
  1435. dlg_listbox_addwithid(ctrl, dlg, options[i].name, options[i].id);
  1436. dlg_listbox_select(ctrl, dlg, 0); /* fallback */
  1437. for (i = 0; i < lenof(options); i++)
  1438. if (val == options[i].id)
  1439. dlg_listbox_select(ctrl, dlg, i);
  1440. #endif
  1441. dlg_update_done(ctrl, dlg);
  1442. } else if (event == EVENT_SELCHANGE
  1443. #ifdef NAMED_CLIPBOARDS
  1444. || event == EVENT_VALCHANGE
  1445. #endif
  1446. ) {
  1447. #ifdef NAMED_CLIPBOARDS
  1448. char *sval = dlg_editbox_get(ctrl, dlg);
  1449. int i;
  1450. for (i = 0; i < lenof(options); i++)
  1451. if (!strcmp(sval, options[i].name)) {
  1452. conf_set_int(conf, setting, options[i].id);
  1453. conf_set_str(conf, strsetting, "");
  1454. break;
  1455. }
  1456. if (i == lenof(options)) {
  1457. conf_set_int(conf, setting, CLIPUI_CUSTOM);
  1458. if (sval[0] == '=')
  1459. sval++;
  1460. conf_set_str(conf, strsetting, sval);
  1461. }
  1462. sfree(sval);
  1463. #else
  1464. int index = dlg_listbox_index(ctrl, dlg);
  1465. if (index >= 0) {
  1466. int val = dlg_listbox_getid(ctrl, dlg, index);
  1467. conf_set_int(conf, setting, val);
  1468. }
  1469. #endif
  1470. }
  1471. }
  1472. static void clipboard_control(struct controlset *s, const char *label,
  1473. char shortcut, int percentage, HelpCtx helpctx,
  1474. int setting, int strsetting)
  1475. {
  1476. #ifdef NAMED_CLIPBOARDS
  1477. ctrl_combobox(s, label, shortcut, percentage, helpctx,
  1478. clipboard_selector_handler, I(setting), I(strsetting));
  1479. #else
  1480. /* strsetting isn't needed in this case */
  1481. ctrl_droplist(s, label, shortcut, percentage, helpctx,
  1482. clipboard_selector_handler, I(setting));
  1483. #endif
  1484. }
  1485. static void serial_parity_handler(dlgcontrol *ctrl, dlgparam *dlg,
  1486. void *data, int event)
  1487. {
  1488. static const struct {
  1489. const char *name;
  1490. int val;
  1491. } parities[] = {
  1492. {"None", SER_PAR_NONE},
  1493. {"Odd", SER_PAR_ODD},
  1494. {"Even", SER_PAR_EVEN},
  1495. {"Mark", SER_PAR_MARK},
  1496. {"Space", SER_PAR_SPACE},
  1497. };
  1498. int mask = ctrl->context.i;
  1499. int i, j;
  1500. Conf *conf = (Conf *)data;
  1501. if (event == EVENT_REFRESH) {
  1502. /* Fetching this once at the start of the function ensures we
  1503. * remember what the right value is supposed to be when
  1504. * operations below cause reentrant calls to this function. */
  1505. int oldparity = conf_get_int(conf, CONF_serparity);
  1506. dlg_update_start(ctrl, dlg);
  1507. dlg_listbox_clear(ctrl, dlg);
  1508. for (i = 0; i < lenof(parities); i++) {
  1509. if (mask & (1 << parities[i].val))
  1510. dlg_listbox_addwithid(ctrl, dlg, parities[i].name,
  1511. parities[i].val);
  1512. }
  1513. for (i = j = 0; i < lenof(parities); i++) {
  1514. if (mask & (1 << parities[i].val)) {
  1515. if (oldparity == parities[i].val) {
  1516. dlg_listbox_select(ctrl, dlg, j);
  1517. break;
  1518. }
  1519. j++;
  1520. }
  1521. }
  1522. if (i == lenof(parities)) { /* an unsupported setting was chosen */
  1523. dlg_listbox_select(ctrl, dlg, 0);
  1524. oldparity = SER_PAR_NONE;
  1525. }
  1526. dlg_update_done(ctrl, dlg);
  1527. conf_set_int(conf, CONF_serparity, oldparity); /* restore */
  1528. } else if (event == EVENT_SELCHANGE) {
  1529. int i = dlg_listbox_index(ctrl, dlg);
  1530. if (i < 0)
  1531. i = SER_PAR_NONE;
  1532. else
  1533. i = dlg_listbox_getid(ctrl, dlg, i);
  1534. conf_set_int(conf, CONF_serparity, i);
  1535. }
  1536. }
  1537. static void serial_flow_handler(dlgcontrol *ctrl, dlgparam *dlg,
  1538. void *data, int event)
  1539. {
  1540. static const struct {
  1541. const char *name;
  1542. int val;
  1543. } flows[] = {
  1544. {"None", SER_FLOW_NONE},
  1545. {"XON/XOFF", SER_FLOW_XONXOFF},
  1546. {"RTS/CTS", SER_FLOW_RTSCTS},
  1547. {"DSR/DTR", SER_FLOW_DSRDTR},
  1548. };
  1549. int mask = ctrl->context.i;
  1550. int i, j;
  1551. Conf *conf = (Conf *)data;
  1552. if (event == EVENT_REFRESH) {
  1553. /* Fetching this once at the start of the function ensures we
  1554. * remember what the right value is supposed to be when
  1555. * operations below cause reentrant calls to this function. */
  1556. int oldflow = conf_get_int(conf, CONF_serflow);
  1557. dlg_update_start(ctrl, dlg);
  1558. dlg_listbox_clear(ctrl, dlg);
  1559. for (i = 0; i < lenof(flows); i++) {
  1560. if (mask & (1 << flows[i].val))
  1561. dlg_listbox_addwithid(ctrl, dlg, flows[i].name, flows[i].val);
  1562. }
  1563. for (i = j = 0; i < lenof(flows); i++) {
  1564. if (mask & (1 << flows[i].val)) {
  1565. if (oldflow == flows[i].val) {
  1566. dlg_listbox_select(ctrl, dlg, j);
  1567. break;
  1568. }
  1569. j++;
  1570. }
  1571. }
  1572. if (i == lenof(flows)) { /* an unsupported setting was chosen */
  1573. dlg_listbox_select(ctrl, dlg, 0);
  1574. oldflow = SER_FLOW_NONE;
  1575. }
  1576. dlg_update_done(ctrl, dlg);
  1577. conf_set_int(conf, CONF_serflow, oldflow);/* restore */
  1578. } else if (event == EVENT_SELCHANGE) {
  1579. int i = dlg_listbox_index(ctrl, dlg);
  1580. if (i < 0)
  1581. i = SER_FLOW_NONE;
  1582. else
  1583. i = dlg_listbox_getid(ctrl, dlg, i);
  1584. conf_set_int(conf, CONF_serflow, i);
  1585. }
  1586. }
  1587. void proxy_type_handler(dlgcontrol *ctrl, dlgparam *dlg,
  1588. void *data, int event)
  1589. {
  1590. Conf *conf = (Conf *)data;
  1591. if (event == EVENT_REFRESH) {
  1592. /*
  1593. * We must fetch the previously configured value from the Conf
  1594. * before we start modifying the drop-down list, otherwise the
  1595. * spurious SELCHANGE we trigger in the process will overwrite
  1596. * the value we wanted to keep.
  1597. */
  1598. int proxy_type = conf_get_int(conf, CONF_proxy_type);
  1599. dlg_update_start(ctrl, dlg);
  1600. dlg_listbox_clear(ctrl, dlg);
  1601. int index_to_select = 0, current_index = 0;
  1602. #define ADD(id, title) do { \
  1603. dlg_listbox_addwithid(ctrl, dlg, title, id); \
  1604. if (id == proxy_type) \
  1605. index_to_select = current_index; \
  1606. current_index++; \
  1607. } while (0)
  1608. ADD(PROXY_NONE, "None");
  1609. ADD(PROXY_SOCKS5, "SOCKS 5");
  1610. ADD(PROXY_SOCKS4, "SOCKS 4");
  1611. ADD(PROXY_HTTP, "HTTP CONNECT");
  1612. if (ssh_proxy_supported) {
  1613. ADD(PROXY_SSH_TCPIP, "SSH to proxy and use port forwarding");
  1614. ADD(PROXY_SSH_EXEC, "SSH to proxy and execute a command");
  1615. ADD(PROXY_SSH_SUBSYSTEM, "SSH to proxy and invoke a subsystem");
  1616. }
  1617. if (ctrl->context.i & PROXY_UI_FLAG_LOCAL) {
  1618. ADD(PROXY_CMD, "Local (run a subprogram to connect)");
  1619. }
  1620. ADD(PROXY_TELNET, "'Telnet' (send an ad-hoc command)");
  1621. #undef ADD
  1622. dlg_listbox_select(ctrl, dlg, index_to_select);
  1623. dlg_update_done(ctrl, dlg);
  1624. } else if (event == EVENT_SELCHANGE) {
  1625. int i = dlg_listbox_index(ctrl, dlg);
  1626. if (i < 0)
  1627. i = AUTO;
  1628. else
  1629. i = dlg_listbox_getid(ctrl, dlg, i);
  1630. conf_set_int(conf, CONF_proxy_type, i);
  1631. }
  1632. }
  1633. static void host_ca_button_handler(dlgcontrol *ctrl, dlgparam *dp,
  1634. void *data, int event)
  1635. {
  1636. if (event == EVENT_ACTION)
  1637. show_ca_config_box(dp);
  1638. }
  1639. void setup_config_box(struct controlbox *b, bool midsession,
  1640. int protocol, int protcfginfo)
  1641. {
  1642. const struct BackendVtable *backvt;
  1643. struct controlset *s;
  1644. struct sessionsaver_data *ssd;
  1645. struct charclass_data *ccd;
  1646. struct colour_data *cd;
  1647. struct ttymodes_data *td;
  1648. struct environ_data *ed;
  1649. struct portfwd_data *pfd;
  1650. struct manual_hostkey_data *mh;
  1651. dlgcontrol *c;
  1652. bool resize_forbidden = false;
  1653. char *str;
  1654. ssd = (struct sessionsaver_data *)
  1655. ctrl_alloc_with_free(b, sizeof(struct sessionsaver_data),
  1656. sessionsaver_data_free);
  1657. memset(ssd, 0, sizeof(*ssd));
  1658. ssd->savedsession = dupstr("");
  1659. ssd->midsession = midsession;
  1660. /*
  1661. * The standard panel that appears at the bottom of all panels:
  1662. * Open, Cancel, Apply etc.
  1663. */
  1664. s = ctrl_getset(b, "", "", "");
  1665. ctrl_columns(s, 5, 20, 20, 20, 20, 20);
  1666. ssd->okbutton = ctrl_pushbutton(s,
  1667. (midsession ? "Apply" : "Open"),
  1668. (char)(midsession ? 'a' : 'o'),
  1669. HELPCTX(no_help),
  1670. sessionsaver_handler, P(ssd));
  1671. ssd->okbutton->button.isdefault = true;
  1672. ssd->okbutton->column = 3;
  1673. ssd->cancelbutton = ctrl_pushbutton(s, "Cancel", 'c', HELPCTX(no_help),
  1674. sessionsaver_handler, P(ssd));
  1675. ssd->cancelbutton->button.iscancel = true;
  1676. ssd->cancelbutton->column = 4;
  1677. /* We carefully don't close the 5-column part, so that platform-
  1678. * specific add-ons can put extra buttons alongside Open and Cancel. */
  1679. /*
  1680. * The Session panel.
  1681. */
  1682. str = dupprintf("Basic options for your %s session", appname);
  1683. ctrl_settitle(b, "Session", str);
  1684. sfree(str);
  1685. if (!midsession) {
  1686. struct hostport *hp = (struct hostport *)
  1687. ctrl_alloc(b, sizeof(struct hostport));
  1688. memset(hp, 0, sizeof(*hp));
  1689. s = ctrl_getset(b, "Session", "hostport",
  1690. "Specify the destination you want to connect to");
  1691. ctrl_columns(s, 2, 75, 25);
  1692. c = ctrl_editbox(s, HOST_BOX_TITLE, 'n', 100,
  1693. HELPCTX(session_hostname),
  1694. config_host_handler, I(0), I(0));
  1695. c->column = 0;
  1696. hp->host = c;
  1697. c = ctrl_editbox(s, PORT_BOX_TITLE, 'p', 100,
  1698. HELPCTX(session_hostname),
  1699. config_port_handler, I(0), I(0));
  1700. c->column = 1;
  1701. hp->port = c;
  1702. ctrl_columns(s, 1, 100);
  1703. c = ctrl_text(s, "Connection type:", HELPCTX(session_hostname));
  1704. ctrl_columns(s, 2, 62, 38);
  1705. c = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
  1706. HELPCTX(session_hostname),
  1707. config_protocols_handler, P(hp));
  1708. c->column = 0;
  1709. hp->protradio = c;
  1710. c->radio.buttons = sresize(c->radio.buttons, PROTOCOL_LIMIT, char *);
  1711. c->radio.shortcuts = sresize(c->radio.shortcuts, PROTOCOL_LIMIT, char);
  1712. c->radio.buttondata = sresize(c->radio.buttondata, PROTOCOL_LIMIT,
  1713. intorptr);
  1714. assert(c->radio.nbuttons == 0);
  1715. /* UI design assumes there exists at least one 'real' radio button */
  1716. assert(n_ui_backends > 0 && n_ui_backends < PROTOCOL_LIMIT);
  1717. for (size_t i = 0; i < n_ui_backends; i++) {
  1718. assert(backends[i]);
  1719. c->radio.buttons[c->radio.nbuttons] =
  1720. dupstr(backends[i]->displayname_tc);
  1721. c->radio.shortcuts[c->radio.nbuttons] =
  1722. (backends[i]->protocol == PROT_SSH ? 's' :
  1723. backends[i]->protocol == PROT_SERIAL ? 'r' :
  1724. backends[i]->protocol == PROT_RAW ? 'w' : /* FIXME unused */
  1725. NO_SHORTCUT);
  1726. c->radio.buttondata[c->radio.nbuttons] =
  1727. I(backends[i]->protocol);
  1728. c->radio.nbuttons++;
  1729. }
  1730. /* UI design assumes there exists at least one droplist entry */
  1731. assert(backends[c->radio.nbuttons]);
  1732. c->radio.buttons[c->radio.nbuttons] = dupstr("Other:");
  1733. c->radio.shortcuts[c->radio.nbuttons] = 't';
  1734. c->radio.buttondata[c->radio.nbuttons] = I(-1);
  1735. c->radio.nbuttons++;
  1736. c = ctrl_droplist(s, NULL, NO_SHORTCUT, 100,
  1737. HELPCTX(session_hostname),
  1738. config_protocols_handler, P(hp));
  1739. hp->protlist = c;
  1740. /* droplist is populated in config_protocols_handler */
  1741. c->column = 1;
  1742. /* Vertically centre the two protocol controls w.r.t. each other */
  1743. hp->protlist->align_next_to = hp->protradio;
  1744. ctrl_columns(s, 1, 100);
  1745. }
  1746. /*
  1747. * The Load/Save panel is available even in mid-session.
  1748. */
  1749. s = ctrl_getset(b, "Session", "savedsessions",
  1750. midsession ? "Save the current session settings" :
  1751. "Load, save or delete a stored session");
  1752. ctrl_columns(s, 2, 75, 25);
  1753. get_sesslist(&ssd->sesslist, true);
  1754. ssd->editbox = ctrl_editbox(s, "Saved Sessions", 'e', 100,
  1755. HELPCTX(session_saved),
  1756. sessionsaver_handler, P(ssd), P(NULL));
  1757. ssd->editbox->column = 0;
  1758. /* Reset columns so that the buttons are alongside the list, rather
  1759. * than alongside that edit box. */
  1760. ctrl_columns(s, 1, 100);
  1761. ctrl_columns(s, 2, 75, 25);
  1762. ssd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
  1763. HELPCTX(session_saved),
  1764. sessionsaver_handler, P(ssd));
  1765. ssd->listbox->column = 0;
  1766. ssd->listbox->listbox.height = 7;
  1767. if (!midsession) {
  1768. ssd->loadbutton = ctrl_pushbutton(s, "Load", 'l',
  1769. HELPCTX(session_saved),
  1770. sessionsaver_handler, P(ssd));
  1771. ssd->loadbutton->column = 1;
  1772. } else {
  1773. /* We can't offer the Load button mid-session, as it would allow the
  1774. * user to load and subsequently save settings they can't see. (And
  1775. * also change otherwise immutable settings underfoot; that probably
  1776. * shouldn't be a problem, but.) */
  1777. ssd->loadbutton = NULL;
  1778. }
  1779. /* "Save" button is permitted mid-session. */
  1780. ssd->savebutton = ctrl_pushbutton(s, "Save", 'v',
  1781. HELPCTX(session_saved),
  1782. sessionsaver_handler, P(ssd));
  1783. ssd->savebutton->column = 1;
  1784. if (!midsession) {
  1785. ssd->delbutton = ctrl_pushbutton(s, "Delete", 'd',
  1786. HELPCTX(session_saved),
  1787. sessionsaver_handler, P(ssd));
  1788. ssd->delbutton->column = 1;
  1789. } else {
  1790. /* Disable the Delete button mid-session too, for UI consistency. */
  1791. ssd->delbutton = NULL;
  1792. }
  1793. ctrl_columns(s, 1, 100);
  1794. s = ctrl_getset(b, "Session", "otheropts", NULL);
  1795. ctrl_radiobuttons(s, "Close window on exit:", 'x', 4,
  1796. HELPCTX(session_coe),
  1797. conf_radiobutton_handler,
  1798. I(CONF_close_on_exit),
  1799. "Always", I(FORCE_ON),
  1800. "Never", I(FORCE_OFF),
  1801. "Only on clean exit", I(AUTO));
  1802. /*
  1803. * The Session/Logging panel.
  1804. */
  1805. ctrl_settitle(b, "Session/Logging", "Options controlling session logging");
  1806. s = ctrl_getset(b, "Session/Logging", "main", NULL);
  1807. /*
  1808. * The logging buttons change depending on whether SSH packet
  1809. * logging can sensibly be available.
  1810. */
  1811. {
  1812. const char *sshlogname, *sshrawlogname;
  1813. if ((midsession && protocol == PROT_SSH) ||
  1814. (!midsession && backend_vt_from_proto(PROT_SSH))) {
  1815. sshlogname = "SSH packets";
  1816. sshrawlogname = "SSH packets and raw data";
  1817. } else {
  1818. sshlogname = NULL; /* this will disable both buttons */
  1819. sshrawlogname = NULL; /* this will just placate optimisers */
  1820. }
  1821. ctrl_radiobuttons(s, "Session logging:", NO_SHORTCUT, 2,
  1822. HELPCTX(logging_main),
  1823. loggingbuttons_handler,
  1824. I(CONF_logtype),
  1825. "None", 't', I(LGTYP_NONE),
  1826. "Printable output", 'p', I(LGTYP_ASCII),
  1827. "All session output", 'l', I(LGTYP_DEBUG),
  1828. sshlogname, 's', I(LGTYP_PACKETS),
  1829. sshrawlogname, 'r', I(LGTYP_SSHRAW));
  1830. }
  1831. ctrl_filesel(s, "Log file name:", 'f',
  1832. NULL, true, "Select session log file name",
  1833. HELPCTX(logging_filename),
  1834. conf_filesel_handler, I(CONF_logfilename));
  1835. ctrl_text(s, "(Log file name can contain &Y, &M, &D for date,"
  1836. " &T for time, &H for host name, and &P for port number)",
  1837. HELPCTX(logging_filename));
  1838. ctrl_radiobuttons(s, "What to do if the log file already exists:", 'e', 1,
  1839. HELPCTX(logging_exists),
  1840. conf_radiobutton_handler, I(CONF_logxfovr),
  1841. "Always overwrite it", I(LGXF_OVR),
  1842. "Always append to the end of it", I(LGXF_APN),
  1843. "Ask the user every time", I(LGXF_ASK));
  1844. ctrl_checkbox(s, "Flush log file frequently", 'u',
  1845. HELPCTX(logging_flush),
  1846. conf_checkbox_handler, I(CONF_logflush));
  1847. ctrl_checkbox(s, "Include header", 'i',
  1848. HELPCTX(logging_header),
  1849. conf_checkbox_handler, I(CONF_logheader));
  1850. if ((midsession && protocol == PROT_SSH) ||
  1851. (!midsession && backend_vt_from_proto(PROT_SSH))) {
  1852. s = ctrl_getset(b, "Session/Logging", "ssh",
  1853. "Options specific to SSH packet logging");
  1854. ctrl_checkbox(s, "Omit known password fields", 'k',
  1855. HELPCTX(logging_ssh_omit_password),
  1856. conf_checkbox_handler, I(CONF_logomitpass));
  1857. ctrl_checkbox(s, "Omit session data", 'd',
  1858. HELPCTX(logging_ssh_omit_data),
  1859. conf_checkbox_handler, I(CONF_logomitdata));
  1860. }
  1861. /*
  1862. * The Terminal panel.
  1863. */
  1864. ctrl_settitle(b, "Terminal", "Options controlling the terminal emulation");
  1865. s = ctrl_getset(b, "Terminal", "general", "Set various terminal options");
  1866. ctrl_checkbox(s, "Auto wrap mode initially on", 'w',
  1867. HELPCTX(terminal_autowrap),
  1868. conf_checkbox_handler, I(CONF_wrap_mode));
  1869. ctrl_checkbox(s, "DEC Origin Mode initially on", 'd',
  1870. HELPCTX(terminal_decom),
  1871. conf_checkbox_handler, I(CONF_dec_om));
  1872. ctrl_checkbox(s, "Implicit CR in every LF", 'r',
  1873. HELPCTX(terminal_lfhascr),
  1874. conf_checkbox_handler, I(CONF_lfhascr));
  1875. ctrl_checkbox(s, "Implicit LF in every CR", 'f',
  1876. HELPCTX(terminal_crhaslf),
  1877. conf_checkbox_handler, I(CONF_crhaslf));
  1878. ctrl_checkbox(s, "Use background colour to erase screen", 'e',
  1879. HELPCTX(terminal_bce),
  1880. conf_checkbox_handler, I(CONF_bce));
  1881. ctrl_checkbox(s, "Enable blinking text", 'n',
  1882. HELPCTX(terminal_blink),
  1883. conf_checkbox_handler, I(CONF_blinktext));
  1884. ctrl_editbox(s, "Answerback to ^E:", 's', 100,
  1885. HELPCTX(terminal_answerback),
  1886. conf_editbox_handler, I(CONF_answerback), ED_STR);
  1887. s = ctrl_getset(b, "Terminal", "ldisc", "Line discipline options");
  1888. ctrl_radiobuttons(s, "Local echo:", 'l', 3,
  1889. HELPCTX(terminal_localecho),
  1890. conf_radiobutton_handler,I(CONF_localecho),
  1891. "Auto", I(AUTO),
  1892. "Force on", I(FORCE_ON),
  1893. "Force off", I(FORCE_OFF));
  1894. ctrl_radiobuttons(s, "Local line editing:", 't', 3,
  1895. HELPCTX(terminal_localedit),
  1896. conf_radiobutton_handler,I(CONF_localedit),
  1897. "Auto", I(AUTO),
  1898. "Force on", I(FORCE_ON),
  1899. "Force off", I(FORCE_OFF));
  1900. s = ctrl_getset(b, "Terminal", "printing", "Remote-controlled printing");
  1901. ctrl_combobox(s, "Printer to send ANSI printer output to:", 'p', 100,
  1902. HELPCTX(terminal_printing),
  1903. printerbox_handler, P(NULL), P(NULL));
  1904. /*
  1905. * The Terminal/Keyboard panel.
  1906. */
  1907. ctrl_settitle(b, "Terminal/Keyboard",
  1908. "Options controlling the effects of keys");
  1909. s = ctrl_getset(b, "Terminal/Keyboard", "mappings",
  1910. "Change the sequences sent by:");
  1911. ctrl_radiobuttons(s, "The Backspace key", 'b', 2,
  1912. HELPCTX(keyboard_backspace),
  1913. conf_radiobutton_bool_handler,
  1914. I(CONF_bksp_is_delete),
  1915. "Control-H", I(0), "Control-? (127)", I(1));
  1916. ctrl_radiobuttons(s, "The Home and End keys", 'e', 2,
  1917. HELPCTX(keyboard_homeend),
  1918. conf_radiobutton_bool_handler,
  1919. I(CONF_rxvt_homeend),
  1920. "Standard", I(false), "rxvt", I(true));
  1921. ctrl_radiobuttons(s, "The Function keys and keypad", 'f', 4,
  1922. HELPCTX(keyboard_funkeys),
  1923. conf_radiobutton_handler,
  1924. I(CONF_funky_type),
  1925. "ESC[n~", I(FUNKY_TILDE),
  1926. "Linux", I(FUNKY_LINUX),
  1927. "Xterm R6", I(FUNKY_XTERM),
  1928. "VT400", I(FUNKY_VT400),
  1929. "VT100+", I(FUNKY_VT100P),
  1930. "SCO", I(FUNKY_SCO),
  1931. "Xterm 216+", I(FUNKY_XTERM_216));
  1932. ctrl_radiobuttons(s, "Shift/Ctrl/Alt with the arrow keys", 'w', 2,
  1933. HELPCTX(keyboard_sharrow),
  1934. conf_radiobutton_handler,
  1935. I(CONF_sharrow_type),
  1936. "Ctrl toggles app mode", I(SHARROW_APPLICATION),
  1937. "xterm-style bitmap", I(SHARROW_BITMAP));
  1938. s = ctrl_getset(b, "Terminal/Keyboard", "appkeypad",
  1939. "Application keypad settings:");
  1940. ctrl_radiobuttons(s, "Initial state of cursor keys:", 'r', 3,
  1941. HELPCTX(keyboard_appcursor),
  1942. conf_radiobutton_bool_handler,
  1943. I(CONF_app_cursor),
  1944. "Normal", I(0), "Application", I(1));
  1945. ctrl_radiobuttons(s, "Initial state of numeric keypad:", 'n', 3,
  1946. HELPCTX(keyboard_appkeypad),
  1947. numeric_keypad_handler, P(NULL),
  1948. "Normal", I(0), "Application", I(1), "NetHack", I(2));
  1949. /*
  1950. * The Terminal/Bell panel.
  1951. */
  1952. ctrl_settitle(b, "Terminal/Bell",
  1953. "Options controlling the terminal bell");
  1954. s = ctrl_getset(b, "Terminal/Bell", "style", "Set the style of bell");
  1955. ctrl_radiobuttons(s, "Action to happen when a bell occurs:", 'b', 1,
  1956. HELPCTX(bell_style),
  1957. conf_radiobutton_handler, I(CONF_beep),
  1958. "None (bell disabled)", I(BELL_DISABLED),
  1959. "Make default system alert sound", I(BELL_DEFAULT),
  1960. "Visual bell (flash window)", I(BELL_VISUAL));
  1961. s = ctrl_getset(b, "Terminal/Bell", "overload",
  1962. "Control the bell overload behaviour");
  1963. ctrl_checkbox(s, "Bell is temporarily disabled when over-used", 'd',
  1964. HELPCTX(bell_overload),
  1965. conf_checkbox_handler, I(CONF_bellovl));
  1966. ctrl_editbox(s, "Over-use means this many bells...", 'm', 20,
  1967. HELPCTX(bell_overload),
  1968. conf_editbox_handler, I(CONF_bellovl_n), ED_INT);
  1969. static const struct conf_editbox_handler_type conf_editbox_tickspersec = {
  1970. .type = EDIT_FIXEDPOINT, .denominator = TICKSPERSEC};
  1971. ctrl_editbox(s, "... in this many seconds", 't', 20,
  1972. HELPCTX(bell_overload),
  1973. conf_editbox_handler, I(CONF_bellovl_t),
  1974. CP(&conf_editbox_tickspersec));
  1975. ctrl_text(s, "The bell is re-enabled after a few seconds of silence.",
  1976. HELPCTX(bell_overload));
  1977. ctrl_editbox(s, "Seconds of silence required", 's', 20,
  1978. HELPCTX(bell_overload),
  1979. conf_editbox_handler, I(CONF_bellovl_s),
  1980. CP(&conf_editbox_tickspersec));
  1981. /*
  1982. * The Terminal/Features panel.
  1983. */
  1984. ctrl_settitle(b, "Terminal/Features",
  1985. "Enabling and disabling advanced terminal features");
  1986. s = ctrl_getset(b, "Terminal/Features", "main", NULL);
  1987. ctrl_checkbox(s, "Disable application cursor keys mode", 'u',
  1988. HELPCTX(features_application),
  1989. conf_checkbox_handler, I(CONF_no_applic_c));
  1990. ctrl_checkbox(s, "Disable application keypad mode", 'k',
  1991. HELPCTX(features_application),
  1992. conf_checkbox_handler, I(CONF_no_applic_k));
  1993. ctrl_checkbox(s, "Disable xterm-style mouse reporting", 'x',
  1994. HELPCTX(features_mouse),
  1995. conf_checkbox_handler, I(CONF_no_mouse_rep));
  1996. ctrl_checkbox(s, "Disable remote-controlled terminal resizing", 's',
  1997. HELPCTX(features_resize),
  1998. conf_checkbox_handler,
  1999. I(CONF_no_remote_resize));
  2000. ctrl_checkbox(s, "Disable switching to alternate terminal screen", 'w',
  2001. HELPCTX(features_altscreen),
  2002. conf_checkbox_handler, I(CONF_no_alt_screen));
  2003. ctrl_checkbox(s, "Disable remote-controlled window title changing", 't',
  2004. HELPCTX(features_retitle),
  2005. conf_checkbox_handler,
  2006. I(CONF_no_remote_wintitle));
  2007. ctrl_radiobuttons(s, "Response to remote title query (SECURITY):", 'q', 3,
  2008. HELPCTX(features_qtitle),
  2009. conf_radiobutton_handler,
  2010. I(CONF_remote_qtitle_action),
  2011. "None", I(TITLE_NONE),
  2012. "Empty string", I(TITLE_EMPTY),
  2013. "Window title", I(TITLE_REAL));
  2014. ctrl_checkbox(s, "Disable remote-controlled clearing of scrollback", 'e',
  2015. HELPCTX(features_clearscroll),
  2016. conf_checkbox_handler,
  2017. I(CONF_no_remote_clearscroll));
  2018. ctrl_checkbox(s, "Disable destructive backspace on server sending ^?",'b',
  2019. HELPCTX(features_dbackspace),
  2020. conf_checkbox_handler, I(CONF_no_dbackspace));
  2021. ctrl_checkbox(s, "Disable remote-controlled character set configuration",
  2022. 'r', HELPCTX(features_charset), conf_checkbox_handler,
  2023. I(CONF_no_remote_charset));
  2024. ctrl_checkbox(s, "Disable Arabic text shaping",
  2025. 'l', HELPCTX(features_arabicshaping), conf_checkbox_handler,
  2026. I(CONF_no_arabicshaping));
  2027. ctrl_checkbox(s, "Disable bidirectional text display",
  2028. 'd', HELPCTX(features_bidi), conf_checkbox_handler,
  2029. I(CONF_no_bidi));
  2030. ctrl_checkbox(s, "Disable bracketed paste mode",
  2031. 'p', HELPCTX(features_bracketed_paste), conf_checkbox_handler,
  2032. I(CONF_no_bracketed_paste));
  2033. /*
  2034. * The Window panel.
  2035. */
  2036. str = dupprintf("Options controlling %s's window", appname);
  2037. ctrl_settitle(b, "Window", str);
  2038. sfree(str);
  2039. backvt = backend_vt_from_proto(protocol);
  2040. if (backvt)
  2041. resize_forbidden = (backvt->flags & BACKEND_RESIZE_FORBIDDEN);
  2042. if (!resize_forbidden || !midsession) {
  2043. s = ctrl_getset(b, "Window", "size", "Set the size of the window");
  2044. ctrl_columns(s, 2, 50, 50);
  2045. c = ctrl_editbox(s, "Columns", 'm', 100,
  2046. HELPCTX(window_size),
  2047. conf_editbox_handler, I(CONF_width), ED_INT);
  2048. c->column = 0;
  2049. c = ctrl_editbox(s, "Rows", 'r', 100,
  2050. HELPCTX(window_size),
  2051. conf_editbox_handler, I(CONF_height),ED_INT);
  2052. c->column = 1;
  2053. ctrl_columns(s, 1, 100);
  2054. }
  2055. s = ctrl_getset(b, "Window", "scrollback",
  2056. "Control the scrollback in the window");
  2057. ctrl_editbox(s, "Lines of scrollback", 's', 50,
  2058. HELPCTX(window_scrollback),
  2059. conf_editbox_handler, I(CONF_savelines), ED_INT);
  2060. ctrl_checkbox(s, "Display scrollbar", 'd',
  2061. HELPCTX(window_scrollback),
  2062. conf_checkbox_handler, I(CONF_scrollbar));
  2063. ctrl_checkbox(s, "Reset scrollback on keypress", 'k',
  2064. HELPCTX(window_scrollback),
  2065. conf_checkbox_handler, I(CONF_scroll_on_key));
  2066. ctrl_checkbox(s, "Reset scrollback on display activity", 'p',
  2067. HELPCTX(window_scrollback),
  2068. conf_checkbox_handler, I(CONF_scroll_on_disp));
  2069. ctrl_checkbox(s, "Push erased text into scrollback", 'e',
  2070. HELPCTX(window_erased),
  2071. conf_checkbox_handler,
  2072. I(CONF_erase_to_scrollback));
  2073. /*
  2074. * The Window/Appearance panel.
  2075. */
  2076. str = dupprintf("Configure the appearance of %s's window", appname);
  2077. ctrl_settitle(b, "Window/Appearance", str);
  2078. sfree(str);
  2079. s = ctrl_getset(b, "Window/Appearance", "cursor",
  2080. "Adjust the use of the cursor");
  2081. ctrl_radiobuttons(s, "Cursor appearance:", NO_SHORTCUT, 3,
  2082. HELPCTX(appearance_cursor),
  2083. conf_radiobutton_handler,
  2084. I(CONF_cursor_type),
  2085. "Block", 'l', I(CURSOR_BLOCK),
  2086. "Underline", 'u', I(CURSOR_UNDERLINE),
  2087. "Vertical line", 'v', I(CURSOR_VERTICAL_LINE));
  2088. ctrl_checkbox(s, "Cursor blinks", 'b',
  2089. HELPCTX(appearance_cursor),
  2090. conf_checkbox_handler, I(CONF_blink_cur));
  2091. s = ctrl_getset(b, "Window/Appearance", "font",
  2092. "Font settings");
  2093. ctrl_fontsel(s, "Font used in the terminal window", 'n',
  2094. HELPCTX(appearance_font),
  2095. conf_fontsel_handler, I(CONF_font));
  2096. s = ctrl_getset(b, "Window/Appearance", "mouse",
  2097. "Adjust the use of the mouse pointer");
  2098. ctrl_checkbox(s, "Hide mouse pointer when typing in window", 'p',
  2099. HELPCTX(appearance_hidemouse),
  2100. conf_checkbox_handler, I(CONF_hide_mouseptr));
  2101. s = ctrl_getset(b, "Window/Appearance", "border",
  2102. "Adjust the window border");
  2103. ctrl_editbox(s, "Gap between text and window edge:", 'e', 20,
  2104. HELPCTX(appearance_border),
  2105. conf_editbox_handler,
  2106. I(CONF_window_border), ED_INT);
  2107. /*
  2108. * The Window/Behaviour panel.
  2109. */
  2110. str = dupprintf("Configure the behaviour of %s's window", appname);
  2111. ctrl_settitle(b, "Window/Behaviour", str);
  2112. sfree(str);
  2113. s = ctrl_getset(b, "Window/Behaviour", "title",
  2114. "Adjust the behaviour of the window title");
  2115. ctrl_editbox(s, "Window title:", 't', 100,
  2116. HELPCTX(appearance_title),
  2117. conf_editbox_handler, I(CONF_wintitle), ED_STR);
  2118. ctrl_checkbox(s, "Separate window and icon titles", 'i',
  2119. HELPCTX(appearance_title),
  2120. conf_checkbox_handler,
  2121. I(CHECKBOX_INVERT | CONF_win_name_always));
  2122. s = ctrl_getset(b, "Window/Behaviour", "main", NULL);
  2123. ctrl_checkbox(s, "Warn before closing window", 'w',
  2124. HELPCTX(behaviour_closewarn),
  2125. conf_checkbox_handler, I(CONF_warn_on_close));
  2126. /*
  2127. * The Window/Translation panel.
  2128. */
  2129. ctrl_settitle(b, "Window/Translation",
  2130. "Options controlling character set translation");
  2131. s = ctrl_getset(b, "Window/Translation", "trans",
  2132. "Character set translation");
  2133. ctrl_combobox(s, "Remote character set:",
  2134. 'r', 100, HELPCTX(translation_codepage),
  2135. codepage_handler, P(NULL), P(NULL));
  2136. s = ctrl_getset(b, "Window/Translation", "tweaks", NULL);
  2137. ctrl_checkbox(s, "Treat CJK ambiguous characters as wide", 'w',
  2138. HELPCTX(translation_cjk_ambig_wide),
  2139. conf_checkbox_handler, I(CONF_cjk_ambig_wide));
  2140. str = dupprintf("Adjust how %s handles line drawing characters", appname);
  2141. s = ctrl_getset(b, "Window/Translation", "linedraw", str);
  2142. sfree(str);
  2143. ctrl_radiobuttons(
  2144. s, "Handling of line drawing characters:", NO_SHORTCUT,1,
  2145. HELPCTX(translation_linedraw),
  2146. conf_radiobutton_handler, I(CONF_vtmode),
  2147. "Use Unicode line drawing code points",'u',I(VT_UNICODE),
  2148. "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN));
  2149. ctrl_checkbox(s, "Copy and paste line drawing characters as lqqqk",'d',
  2150. HELPCTX(selection_linedraw),
  2151. conf_checkbox_handler, I(CONF_rawcnp));
  2152. ctrl_checkbox(s, "Enable VT100 line drawing even in UTF-8 mode",'8',
  2153. HELPCTX(translation_utf8linedraw),
  2154. conf_checkbox_handler, I(CONF_utf8linedraw));
  2155. /*
  2156. * The Window/Selection panel.
  2157. */
  2158. ctrl_settitle(b, "Window/Selection", "Options controlling copy and paste");
  2159. s = ctrl_getset(b, "Window/Selection", "mouse",
  2160. "Control use of mouse");
  2161. ctrl_checkbox(s, "Shift overrides application's use of mouse", 'p',
  2162. HELPCTX(selection_shiftdrag),
  2163. conf_checkbox_handler, I(CONF_mouse_override));
  2164. ctrl_radiobuttons(s,
  2165. "Default selection mode (Alt+drag does the other one):",
  2166. NO_SHORTCUT, 2,
  2167. HELPCTX(selection_rect),
  2168. conf_radiobutton_bool_handler,
  2169. I(CONF_rect_select),
  2170. "Normal", 'n', I(false),
  2171. "Rectangular block", 'r', I(true));
  2172. s = ctrl_getset(b, "Window/Selection", "clipboards",
  2173. "Assign copy/paste actions to clipboards");
  2174. ctrl_checkbox(s, "Auto-copy selected text to "
  2175. CLIPNAME_EXPLICIT_OBJECT,
  2176. NO_SHORTCUT, HELPCTX(selection_autocopy),
  2177. conf_checkbox_handler, I(CONF_mouseautocopy));
  2178. clipboard_control(s, "Mouse paste action:", NO_SHORTCUT, 60,
  2179. HELPCTX(selection_clipactions),
  2180. CONF_mousepaste, CONF_mousepaste_custom);
  2181. clipboard_control(s, "{Ctrl,Shift} + Ins:", NO_SHORTCUT, 60,
  2182. HELPCTX(selection_clipactions),
  2183. CONF_ctrlshiftins, CONF_ctrlshiftins_custom);
  2184. clipboard_control(s, "Ctrl + Shift + {C,V}:", NO_SHORTCUT, 60,
  2185. HELPCTX(selection_clipactions),
  2186. CONF_ctrlshiftcv, CONF_ctrlshiftcv_custom);
  2187. s = ctrl_getset(b, "Window/Selection", "paste",
  2188. "Control pasting of text from clipboard to terminal");
  2189. ctrl_checkbox(s, "Permit control characters in pasted text",
  2190. NO_SHORTCUT, HELPCTX(selection_pastectrl),
  2191. conf_checkbox_handler, I(CONF_paste_controls));
  2192. /*
  2193. * The Window/Selection/Copy panel.
  2194. */
  2195. ctrl_settitle(b, "Window/Selection/Copy",
  2196. "Options controlling copying from terminal to clipboard");
  2197. s = ctrl_getset(b, "Window/Selection/Copy", "charclass",
  2198. "Classes of character that group together");
  2199. ccd = (struct charclass_data *)
  2200. ctrl_alloc(b, sizeof(struct charclass_data));
  2201. ccd->listbox = ctrl_listbox(s, "Character classes:", 'e',
  2202. HELPCTX(copy_charclasses),
  2203. charclass_handler, P(ccd));
  2204. ccd->listbox->listbox.multisel = 1;
  2205. ccd->listbox->listbox.ncols = 4;
  2206. ccd->listbox->listbox.percentages = snewn(4, int);
  2207. ccd->listbox->listbox.percentages[0] = 15;
  2208. ccd->listbox->listbox.percentages[1] = 25;
  2209. ccd->listbox->listbox.percentages[2] = 20;
  2210. ccd->listbox->listbox.percentages[3] = 40;
  2211. ctrl_columns(s, 2, 67, 33);
  2212. ccd->editbox = ctrl_editbox(s, "Set to class", 't', 50,
  2213. HELPCTX(copy_charclasses),
  2214. charclass_handler, P(ccd), P(NULL));
  2215. ccd->editbox->column = 0;
  2216. ccd->button = ctrl_pushbutton(s, "Set", 's',
  2217. HELPCTX(copy_charclasses),
  2218. charclass_handler, P(ccd));
  2219. ccd->button->column = 1;
  2220. ctrl_columns(s, 1, 100);
  2221. /*
  2222. * The Window/Colours panel.
  2223. */
  2224. ctrl_settitle(b, "Window/Colours", "Options controlling use of colours");
  2225. s = ctrl_getset(b, "Window/Colours", "general",
  2226. "General options for colour usage");
  2227. ctrl_checkbox(s, "Allow terminal to specify ANSI colours", 'i',
  2228. HELPCTX(colours_ansi),
  2229. conf_checkbox_handler, I(CONF_ansi_colour));
  2230. ctrl_checkbox(s, "Allow terminal to use xterm 256-colour mode", '2',
  2231. HELPCTX(colours_xterm256), conf_checkbox_handler,
  2232. I(CONF_xterm_256_colour));
  2233. ctrl_checkbox(s, "Allow terminal to use 24-bit colours", '4',
  2234. HELPCTX(colours_truecolour), conf_checkbox_handler,
  2235. I(CONF_true_colour));
  2236. ctrl_radiobuttons(s, "Indicate bolded text by changing:", 'b', 3,
  2237. HELPCTX(colours_bold),
  2238. conf_radiobutton_handler, I(CONF_bold_style),
  2239. "The font", I(BOLD_STYLE_FONT),
  2240. "The colour", I(BOLD_STYLE_COLOUR),
  2241. "Both", I(BOLD_STYLE_FONT | BOLD_STYLE_COLOUR));
  2242. str = dupprintf("Adjust the precise colours %s displays", appname);
  2243. s = ctrl_getset(b, "Window/Colours", "adjust", str);
  2244. sfree(str);
  2245. ctrl_text(s, "Select a colour from the list, and then click the"
  2246. " Modify button to change its appearance.",
  2247. HELPCTX(colours_config));
  2248. ctrl_columns(s, 2, 67, 33);
  2249. cd = (struct colour_data *)ctrl_alloc(b, sizeof(struct colour_data));
  2250. cd->listbox = ctrl_listbox(s, "Select a colour to adjust:", 'u',
  2251. HELPCTX(colours_config), colour_handler, P(cd));
  2252. cd->listbox->column = 0;
  2253. cd->listbox->listbox.height = 7;
  2254. c = ctrl_text(s, "RGB value:", HELPCTX(colours_config));
  2255. c->column = 1;
  2256. cd->redit = ctrl_editbox(s, "Red", 'r', 50, HELPCTX(colours_config),
  2257. colour_handler, P(cd), P(NULL));
  2258. cd->redit->column = 1;
  2259. cd->gedit = ctrl_editbox(s, "Green", 'n', 50, HELPCTX(colours_config),
  2260. colour_handler, P(cd), P(NULL));
  2261. cd->gedit->column = 1;
  2262. cd->bedit = ctrl_editbox(s, "Blue", 'e', 50, HELPCTX(colours_config),
  2263. colour_handler, P(cd), P(NULL));
  2264. cd->bedit->column = 1;
  2265. cd->button = ctrl_pushbutton(s, "Modify", 'm', HELPCTX(colours_config),
  2266. colour_handler, P(cd));
  2267. cd->button->column = 1;
  2268. ctrl_columns(s, 1, 100);
  2269. /*
  2270. * The Connection panel. This doesn't show up if we're in a
  2271. * non-network utility such as pterm. We tell this by being
  2272. * passed a protocol < 0.
  2273. */
  2274. if (protocol >= 0) {
  2275. ctrl_settitle(b, "Connection", "Options controlling the connection");
  2276. s = ctrl_getset(b, "Connection", "keepalive",
  2277. "Sending of null packets to keep session active");
  2278. ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
  2279. HELPCTX(connection_keepalive),
  2280. conf_editbox_handler, I(CONF_ping_interval), ED_INT);
  2281. if (!midsession) {
  2282. s = ctrl_getset(b, "Connection", "tcp",
  2283. "Low-level TCP connection options");
  2284. ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)",
  2285. 'n', HELPCTX(connection_nodelay),
  2286. conf_checkbox_handler,
  2287. I(CONF_tcp_nodelay));
  2288. ctrl_checkbox(s, "Enable TCP keepalives (SO_KEEPALIVE option)",
  2289. 'p', HELPCTX(connection_tcpkeepalive),
  2290. conf_checkbox_handler,
  2291. I(CONF_tcp_keepalives));
  2292. #ifndef NO_IPV6
  2293. s = ctrl_getset(b, "Connection", "ipversion",
  2294. "Internet protocol version");
  2295. ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
  2296. HELPCTX(connection_ipversion),
  2297. conf_radiobutton_handler,
  2298. I(CONF_addressfamily),
  2299. "Auto", 'u', I(ADDRTYPE_UNSPEC),
  2300. "IPv4", '4', I(ADDRTYPE_IPV4),
  2301. "IPv6", '6', I(ADDRTYPE_IPV6));
  2302. #endif
  2303. {
  2304. const char *label = backend_vt_from_proto(PROT_SSH) ?
  2305. "Logical name of remote host (e.g. for SSH key lookup):" :
  2306. "Logical name of remote host:";
  2307. s = ctrl_getset(b, "Connection", "identity",
  2308. "Logical name of remote host");
  2309. ctrl_editbox(s, label, 'm', 100,
  2310. HELPCTX(connection_loghost),
  2311. conf_editbox_handler, I(CONF_loghost), ED_STR);
  2312. }
  2313. }
  2314. /*
  2315. * A sub-panel Connection/Data, containing options that
  2316. * decide on data to send to the server.
  2317. */
  2318. if (!midsession) {
  2319. ctrl_settitle(b, "Connection/Data", "Data to send to the server");
  2320. s = ctrl_getset(b, "Connection/Data", "login",
  2321. "Login details");
  2322. ctrl_editbox(s, "Auto-login username", 'u', 50,
  2323. HELPCTX(connection_username),
  2324. conf_editbox_handler, I(CONF_username), ED_STR);
  2325. {
  2326. /* We assume the local username is sufficiently stable
  2327. * to include on the dialog box. */
  2328. char *user = get_username();
  2329. char *userlabel = dupprintf("Use system username (%s)",
  2330. user ? user : "");
  2331. sfree(user);
  2332. ctrl_radiobuttons(s, "When username is not specified:", 'n', 4,
  2333. HELPCTX(connection_username_from_env),
  2334. conf_radiobutton_bool_handler,
  2335. I(CONF_username_from_env),
  2336. "Prompt", I(false),
  2337. userlabel, I(true));
  2338. sfree(userlabel);
  2339. }
  2340. s = ctrl_getset(b, "Connection/Data", "term",
  2341. "Terminal details");
  2342. ctrl_editbox(s, "Terminal-type string", 't', 50,
  2343. HELPCTX(connection_termtype),
  2344. conf_editbox_handler, I(CONF_termtype), ED_STR);
  2345. ctrl_editbox(s, "Terminal speeds", 's', 50,
  2346. HELPCTX(connection_termspeed),
  2347. conf_editbox_handler, I(CONF_termspeed), ED_STR);
  2348. s = ctrl_getset(b, "Connection/Data", "env",
  2349. "Environment variables");
  2350. ctrl_columns(s, 2, 80, 20);
  2351. ed = (struct environ_data *)
  2352. ctrl_alloc(b, sizeof(struct environ_data));
  2353. ed->varbox = ctrl_editbox(s, "Variable", 'v', 60,
  2354. HELPCTX(telnet_environ),
  2355. environ_handler, P(ed), P(NULL));
  2356. ed->varbox->column = 0;
  2357. ed->valbox = ctrl_editbox(s, "Value", 'l', 60,
  2358. HELPCTX(telnet_environ),
  2359. environ_handler, P(ed), P(NULL));
  2360. ed->valbox->column = 0;
  2361. ed->addbutton = ctrl_pushbutton(s, "Add", 'd',
  2362. HELPCTX(telnet_environ),
  2363. environ_handler, P(ed));
  2364. ed->addbutton->column = 1;
  2365. ed->rembutton = ctrl_pushbutton(s, "Remove", 'r',
  2366. HELPCTX(telnet_environ),
  2367. environ_handler, P(ed));
  2368. ed->rembutton->column = 1;
  2369. ctrl_columns(s, 1, 100);
  2370. ed->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
  2371. HELPCTX(telnet_environ),
  2372. environ_handler, P(ed));
  2373. ed->listbox->listbox.height = 3;
  2374. ed->listbox->listbox.ncols = 2;
  2375. ed->listbox->listbox.percentages = snewn(2, int);
  2376. ed->listbox->listbox.percentages[0] = 30;
  2377. ed->listbox->listbox.percentages[1] = 70;
  2378. }
  2379. }
  2380. if (!midsession) {
  2381. /*
  2382. * The Connection/Proxy panel.
  2383. */
  2384. ctrl_settitle(b, "Connection/Proxy",
  2385. "Options controlling proxy usage");
  2386. s = ctrl_getset(b, "Connection/Proxy", "basics", NULL);
  2387. c = ctrl_droplist(s, "Proxy type:", 't', 70,
  2388. HELPCTX(proxy_type), proxy_type_handler, I(0));
  2389. ctrl_columns(s, 2, 80, 20);
  2390. c = ctrl_editbox(s, "Proxy hostname", 'y', 100,
  2391. HELPCTX(proxy_main),
  2392. conf_editbox_handler,
  2393. I(CONF_proxy_host), ED_STR);
  2394. c->column = 0;
  2395. c = ctrl_editbox(s, "Port", 'p', 100,
  2396. HELPCTX(proxy_main),
  2397. conf_editbox_handler,
  2398. I(CONF_proxy_port),
  2399. ED_INT);
  2400. c->column = 1;
  2401. ctrl_columns(s, 1, 100);
  2402. ctrl_editbox(s, "Exclude Hosts/IPs", 'e', 100,
  2403. HELPCTX(proxy_exclude),
  2404. conf_editbox_handler,
  2405. I(CONF_proxy_exclude_list), ED_STR);
  2406. ctrl_checkbox(s, "Consider proxying local host connections", 'x',
  2407. HELPCTX(proxy_exclude),
  2408. conf_checkbox_handler,
  2409. I(CONF_even_proxy_localhost));
  2410. ctrl_radiobuttons(s, "Do DNS name lookup at proxy end:", 'd', 3,
  2411. HELPCTX(proxy_dns),
  2412. conf_radiobutton_handler,
  2413. I(CONF_proxy_dns),
  2414. "No", I(FORCE_OFF),
  2415. "Auto", I(AUTO),
  2416. "Yes", I(FORCE_ON));
  2417. ctrl_editbox(s, "Username", 'u', 60,
  2418. HELPCTX(proxy_auth),
  2419. conf_editbox_handler,
  2420. I(CONF_proxy_username), ED_STR);
  2421. c = ctrl_editbox(s, "Password", 'w', 60,
  2422. HELPCTX(proxy_auth),
  2423. conf_editbox_handler,
  2424. I(CONF_proxy_password), ED_STR);
  2425. c->editbox.password = true;
  2426. ctrl_editbox(s, "Command to send to proxy (for some types)", 'm', 100,
  2427. HELPCTX(proxy_command),
  2428. conf_editbox_handler,
  2429. I(CONF_proxy_telnet_command), ED_STR);
  2430. ctrl_radiobuttons(s, "Print proxy diagnostics "
  2431. "in the terminal window", 'r', 5,
  2432. HELPCTX(proxy_logging),
  2433. conf_radiobutton_handler,
  2434. I(CONF_proxy_log_to_term),
  2435. "No", I(FORCE_OFF),
  2436. "Yes", I(FORCE_ON),
  2437. "Only until session starts", I(AUTO));
  2438. }
  2439. /*
  2440. * Each per-protocol configuration GUI panel is conditionally
  2441. * displayed. We don't display it if this binary doesn't contain a
  2442. * backend for its protocol at all; we don't display it if we're
  2443. * already in mid-session with a different protocol selected; and
  2444. * even if we _do_ have this protocol selected, we don't display
  2445. * the panel if the protocol doesn't permit any mid-session
  2446. * reconfiguration anyway.
  2447. */
  2448. #define DISPLAY_RECONFIGURABLE_PROTOCOL(which_proto) \
  2449. (backend_vt_from_proto(which_proto) && \
  2450. (!midsession || protocol == (which_proto)))
  2451. #define DISPLAY_NON_RECONFIGURABLE_PROTOCOL(which_proto) \
  2452. (backend_vt_from_proto(which_proto) && !midsession)
  2453. if (DISPLAY_RECONFIGURABLE_PROTOCOL(PROT_SSH) ||
  2454. DISPLAY_RECONFIGURABLE_PROTOCOL(PROT_SSHCONN)) {
  2455. /*
  2456. * The Connection/SSH panel.
  2457. */
  2458. ctrl_settitle(b, "Connection/SSH",
  2459. "Options controlling SSH connections");
  2460. /* SSH-1 or connection-sharing downstream */
  2461. if (midsession && (protcfginfo == 1 || protcfginfo == -1)) {
  2462. s = ctrl_getset(b, "Connection/SSH", "disclaimer", NULL);
  2463. ctrl_text(s, "Nothing on this panel may be reconfigured in mid-"
  2464. "session; it is only here so that sub-panels of it can "
  2465. "exist without looking strange.", HELPCTX(no_help));
  2466. }
  2467. if (!midsession) {
  2468. s = ctrl_getset(b, "Connection/SSH", "data",
  2469. "Data to send to the server");
  2470. ctrl_editbox(s, "Remote command:", 'r', 100,
  2471. HELPCTX(ssh_command),
  2472. conf_editbox_handler, I(CONF_remote_cmd), ED_STR);
  2473. s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
  2474. ctrl_checkbox(s, "Don't start a shell or command at all", 'n',
  2475. HELPCTX(ssh_noshell),
  2476. conf_checkbox_handler,
  2477. I(CONF_ssh_no_shell));
  2478. }
  2479. if (!midsession || !(protcfginfo == 1 || protcfginfo == -1)) {
  2480. s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
  2481. ctrl_checkbox(s, "Enable compression", 'e',
  2482. HELPCTX(ssh_compress),
  2483. conf_checkbox_handler,
  2484. I(CONF_compression));
  2485. }
  2486. if (!midsession) {
  2487. s = ctrl_getset(b, "Connection/SSH", "sharing", "Sharing an SSH connection between PuTTY tools");
  2488. ctrl_checkbox(s, "Share SSH connections if possible", 's',
  2489. HELPCTX(ssh_share),
  2490. conf_checkbox_handler,
  2491. I(CONF_ssh_connection_sharing));
  2492. ctrl_text(s, "Permitted roles in a shared connection:",
  2493. HELPCTX(ssh_share));
  2494. ctrl_checkbox(s, "Upstream (connecting to the real server)", 'u',
  2495. HELPCTX(ssh_share),
  2496. conf_checkbox_handler,
  2497. I(CONF_ssh_connection_sharing_upstream));
  2498. ctrl_checkbox(s, "Downstream (connecting to the upstream PuTTY)", 'd',
  2499. HELPCTX(ssh_share),
  2500. conf_checkbox_handler,
  2501. I(CONF_ssh_connection_sharing_downstream));
  2502. }
  2503. if (!midsession) {
  2504. s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
  2505. ctrl_radiobuttons(s, "SSH protocol version:", NO_SHORTCUT, 2,
  2506. HELPCTX(ssh_protocol),
  2507. conf_radiobutton_handler,
  2508. I(CONF_sshprot),
  2509. "2", '2', I(3),
  2510. "1 (INSECURE)", '1', I(0));
  2511. }
  2512. /*
  2513. * The Connection/SSH/Kex panel. (Owing to repeat key
  2514. * exchange, much of this is meaningful in mid-session _if_
  2515. * we're using SSH-2 and are not a connection-sharing
  2516. * downstream, or haven't decided yet.)
  2517. */
  2518. if (protcfginfo != 1 && protcfginfo != -1) {
  2519. ctrl_settitle(b, "Connection/SSH/Kex",
  2520. "Options controlling SSH key exchange");
  2521. s = ctrl_getset(b, "Connection/SSH/Kex", "main",
  2522. "Key exchange algorithm options");
  2523. c = ctrl_draglist(s, "Algorithm selection policy:", 's',
  2524. HELPCTX(ssh_kexlist),
  2525. kexlist_handler, P(NULL));
  2526. c->listbox.height = KEX_MAX;
  2527. #ifndef NO_GSSAPI
  2528. ctrl_checkbox(s, "Attempt GSSAPI key exchange",
  2529. 'k', HELPCTX(ssh_gssapi),
  2530. conf_checkbox_handler,
  2531. I(CONF_try_gssapi_kex));
  2532. #endif
  2533. s = ctrl_getset(b, "Connection/SSH/Kex", "repeat",
  2534. "Options controlling key re-exchange");
  2535. ctrl_editbox(s, "Max minutes before rekey (0 for no limit)", 't', 20,
  2536. HELPCTX(ssh_kex_repeat),
  2537. conf_editbox_handler,
  2538. I(CONF_ssh_rekey_time),
  2539. ED_INT);
  2540. #ifndef NO_GSSAPI
  2541. ctrl_editbox(s, "Minutes between GSS checks (0 for never)", NO_SHORTCUT, 20,
  2542. HELPCTX(ssh_kex_repeat),
  2543. conf_editbox_handler,
  2544. I(CONF_gssapirekey),
  2545. ED_INT);
  2546. #endif
  2547. ctrl_editbox(s, "Max data before rekey (0 for no limit)", 'x', 20,
  2548. HELPCTX(ssh_kex_repeat),
  2549. conf_editbox_handler,
  2550. I(CONF_ssh_rekey_data),
  2551. ED_STR);
  2552. ctrl_text(s, "(Use 1M for 1 megabyte, 1G for 1 gigabyte etc)",
  2553. HELPCTX(ssh_kex_repeat));
  2554. }
  2555. /*
  2556. * The 'Connection/SSH/Host keys' panel.
  2557. */
  2558. if (protcfginfo != 1 && protcfginfo != -1) {
  2559. ctrl_settitle(b, "Connection/SSH/Host keys",
  2560. "Options controlling SSH host keys");
  2561. s = ctrl_getset(b, "Connection/SSH/Host keys", "main",
  2562. "Host key algorithm preference");
  2563. c = ctrl_draglist(s, "Algorithm selection policy:", 's',
  2564. HELPCTX(ssh_hklist),
  2565. hklist_handler, P(NULL));
  2566. c->listbox.height = 5;
  2567. ctrl_checkbox(s, "Prefer algorithms for which a host key is known",
  2568. 'p', HELPCTX(ssh_hk_known), conf_checkbox_handler,
  2569. I(CONF_ssh_prefer_known_hostkeys));
  2570. }
  2571. /*
  2572. * Manual host key configuration is irrelevant mid-session,
  2573. * as we enforce that the host key for rekeys is the
  2574. * same as that used at the start of the session.
  2575. */
  2576. if (!midsession) {
  2577. s = ctrl_getset(b, "Connection/SSH/Host keys", "hostkeys",
  2578. "Manually configure host keys for this connection");
  2579. ctrl_columns(s, 2, 75, 25);
  2580. c = ctrl_text(s, "Host keys or fingerprints to accept:",
  2581. HELPCTX(ssh_kex_manual_hostkeys));
  2582. c->column = 0;
  2583. /* You want to select from the list, _then_ hit Remove. So
  2584. * tab order should be that way round. */
  2585. mh = (struct manual_hostkey_data *)
  2586. ctrl_alloc(b,sizeof(struct manual_hostkey_data));
  2587. mh->rembutton = ctrl_pushbutton(s, "Remove", 'r',
  2588. HELPCTX(ssh_kex_manual_hostkeys),
  2589. manual_hostkey_handler, P(mh));
  2590. mh->rembutton->column = 1;
  2591. mh->rembutton->delay_taborder = true;
  2592. mh->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
  2593. HELPCTX(ssh_kex_manual_hostkeys),
  2594. manual_hostkey_handler, P(mh));
  2595. /* This list box can't be very tall, because there's not
  2596. * much room in the pane on Windows at least. This makes
  2597. * it become really unhelpful if a horizontal scrollbar
  2598. * appears, so we suppress that. */
  2599. mh->listbox->listbox.height = 2;
  2600. mh->listbox->listbox.hscroll = false;
  2601. ctrl_tabdelay(s, mh->rembutton);
  2602. mh->keybox = ctrl_editbox(s, "Key", 'k', 80,
  2603. HELPCTX(ssh_kex_manual_hostkeys),
  2604. manual_hostkey_handler, P(mh), P(NULL));
  2605. mh->keybox->column = 0;
  2606. mh->addbutton = ctrl_pushbutton(s, "Add key", 'y',
  2607. HELPCTX(ssh_kex_manual_hostkeys),
  2608. manual_hostkey_handler, P(mh));
  2609. mh->addbutton->column = 1;
  2610. ctrl_columns(s, 1, 100);
  2611. }
  2612. /*
  2613. * But there's no reason not to forbid access to the host CA
  2614. * configuration box, which is common across sessions in any
  2615. * case.
  2616. */
  2617. s = ctrl_getset(b, "Connection/SSH/Host keys", "ca",
  2618. "Configure trusted certification authorities");
  2619. c = ctrl_pushbutton(s, "Configure host CAs", NO_SHORTCUT,
  2620. HELPCTX(ssh_kex_cert),
  2621. host_ca_button_handler, I(0));
  2622. if (!midsession || !(protcfginfo == 1 || protcfginfo == -1)) {
  2623. /*
  2624. * The Connection/SSH/Cipher panel.
  2625. */
  2626. ctrl_settitle(b, "Connection/SSH/Cipher",
  2627. "Options controlling SSH encryption");
  2628. s = ctrl_getset(b, "Connection/SSH/Cipher",
  2629. "encryption", "Encryption options");
  2630. c = ctrl_draglist(s, "Encryption cipher selection policy:", 's',
  2631. HELPCTX(ssh_ciphers),
  2632. cipherlist_handler, P(NULL));
  2633. c->listbox.height = 6;
  2634. ctrl_checkbox(s, "Enable legacy use of single-DES in SSH-2", 'i',
  2635. HELPCTX(ssh_ciphers),
  2636. conf_checkbox_handler,
  2637. I(CONF_ssh2_des_cbc));
  2638. }
  2639. if (!midsession) {
  2640. /*
  2641. * The Connection/SSH/Auth panel.
  2642. */
  2643. ctrl_settitle(b, "Connection/SSH/Auth",
  2644. "Options controlling SSH authentication");
  2645. s = ctrl_getset(b, "Connection/SSH/Auth", "main", NULL);
  2646. ctrl_checkbox(s, "Display pre-authentication banner (SSH-2 only)",
  2647. 'd', HELPCTX(ssh_auth_banner),
  2648. conf_checkbox_handler,
  2649. I(CONF_ssh_show_banner));
  2650. ctrl_checkbox(s, "Bypass authentication entirely (SSH-2 only)", 'b',
  2651. HELPCTX(ssh_auth_bypass),
  2652. conf_checkbox_handler,
  2653. I(CONF_ssh_no_userauth));
  2654. ctrl_checkbox(s, "Disconnect if authentication succeeds trivially",
  2655. 'n', HELPCTX(ssh_no_trivial_userauth),
  2656. conf_checkbox_handler,
  2657. I(CONF_ssh_no_trivial_userauth));
  2658. s = ctrl_getset(b, "Connection/SSH/Auth", "methods",
  2659. "Authentication methods");
  2660. ctrl_checkbox(s, "Attempt authentication using Pageant", 'p',
  2661. HELPCTX(ssh_auth_pageant),
  2662. conf_checkbox_handler,
  2663. I(CONF_tryagent));
  2664. ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH-1)", 'm',
  2665. HELPCTX(ssh_auth_tis),
  2666. conf_checkbox_handler,
  2667. I(CONF_try_tis_auth));
  2668. ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH-2)",
  2669. 'i', HELPCTX(ssh_auth_ki),
  2670. conf_checkbox_handler,
  2671. I(CONF_try_ki_auth));
  2672. s = ctrl_getset(b, "Connection/SSH/Auth", "aux",
  2673. "Other authentication-related options");
  2674. ctrl_checkbox(s, "Allow agent forwarding", 'f',
  2675. HELPCTX(ssh_auth_agentfwd),
  2676. conf_checkbox_handler, I(CONF_agentfwd));
  2677. ctrl_checkbox(s, "Allow attempted changes of username in SSH-2", NO_SHORTCUT,
  2678. HELPCTX(ssh_auth_changeuser),
  2679. conf_checkbox_handler,
  2680. I(CONF_change_username));
  2681. ctrl_settitle(b, "Connection/SSH/Auth/Credentials",
  2682. "Credentials to authenticate with");
  2683. s = ctrl_getset(b, "Connection/SSH/Auth/Credentials", "publickey",
  2684. "Public-key authentication");
  2685. ctrl_filesel(s, "Private key file for authentication:", 'k',
  2686. FILTER_KEY_FILES, false, "Select private key file",
  2687. HELPCTX(ssh_auth_privkey),
  2688. conf_filesel_handler, I(CONF_keyfile));
  2689. ctrl_filesel(s, "Certificate to use with the private key "
  2690. "(optional):", 'e',
  2691. NULL, false, "Select certificate file",
  2692. HELPCTX(ssh_auth_cert),
  2693. conf_filesel_handler, I(CONF_detached_cert));
  2694. s = ctrl_getset(b, "Connection/SSH/Auth/Credentials", "plugin",
  2695. "Plugin to provide authentication responses");
  2696. ctrl_editbox(s, "Plugin command to run", NO_SHORTCUT, 100,
  2697. HELPCTX(ssh_auth_plugin),
  2698. conf_editbox_handler, I(CONF_auth_plugin), ED_STR);
  2699. #ifndef NO_GSSAPI
  2700. /*
  2701. * Connection/SSH/Auth/GSSAPI, which sadly won't fit on
  2702. * the main Auth panel.
  2703. */
  2704. ctrl_settitle(b, "Connection/SSH/Auth/GSSAPI",
  2705. "Options controlling GSSAPI authentication");
  2706. s = ctrl_getset(b, "Connection/SSH/Auth/GSSAPI", "gssapi", NULL);
  2707. ctrl_checkbox(s, "Attempt GSSAPI authentication (SSH-2 only)",
  2708. 't', HELPCTX(ssh_gssapi),
  2709. conf_checkbox_handler,
  2710. I(CONF_try_gssapi_auth));
  2711. ctrl_checkbox(s, "Attempt GSSAPI key exchange (SSH-2 only)",
  2712. 'k', HELPCTX(ssh_gssapi),
  2713. conf_checkbox_handler,
  2714. I(CONF_try_gssapi_kex));
  2715. ctrl_checkbox(s, "Allow GSSAPI credential delegation", 'l',
  2716. HELPCTX(ssh_gssapi_delegation),
  2717. conf_checkbox_handler,
  2718. I(CONF_gssapifwd));
  2719. /*
  2720. * GSSAPI library selection.
  2721. */
  2722. if (ngsslibs > 1) {
  2723. c = ctrl_draglist(s, "Preference order for GSSAPI libraries:",
  2724. 'p', HELPCTX(ssh_gssapi_libraries),
  2725. gsslist_handler, P(NULL));
  2726. c->listbox.height = ngsslibs;
  2727. /*
  2728. * I currently assume that if more than one GSS
  2729. * library option is available, then one of them is
  2730. * 'user-supplied' and so we should present the
  2731. * following file selector. This is at least half-
  2732. * reasonable, because if we're using statically
  2733. * linked GSSAPI then there will only be one option
  2734. * and no way to load from a user-supplied library,
  2735. * whereas if we're using dynamic libraries then
  2736. * there will almost certainly be some default
  2737. * option in addition to a user-supplied path. If
  2738. * anyone ever ports PuTTY to a system on which
  2739. * dynamic-library GSSAPI is available but there is
  2740. * absolutely no consensus on where to keep the
  2741. * libraries, there'll need to be a flag alongside
  2742. * ngsslibs to control whether the file selector is
  2743. * displayed.
  2744. */
  2745. ctrl_filesel(s, "User-supplied GSSAPI library path:", 's',
  2746. FILTER_DYNLIB_FILES, false, "Select library file",
  2747. HELPCTX(ssh_gssapi_libraries),
  2748. conf_filesel_handler,
  2749. I(CONF_ssh_gss_custom));
  2750. }
  2751. #endif
  2752. }
  2753. if (!midsession) {
  2754. /*
  2755. * The Connection/SSH/TTY panel.
  2756. */
  2757. ctrl_settitle(b, "Connection/SSH/TTY", "Remote terminal settings");
  2758. s = ctrl_getset(b, "Connection/SSH/TTY", "sshtty", NULL);
  2759. ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p',
  2760. HELPCTX(ssh_nopty),
  2761. conf_checkbox_handler,
  2762. I(CONF_nopty));
  2763. s = ctrl_getset(b, "Connection/SSH/TTY", "ttymodes",
  2764. "Terminal modes");
  2765. td = (struct ttymodes_data *)
  2766. ctrl_alloc(b, sizeof(struct ttymodes_data));
  2767. ctrl_text(s, "Terminal modes to send:", HELPCTX(ssh_ttymodes));
  2768. td->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
  2769. HELPCTX(ssh_ttymodes),
  2770. ttymodes_handler, P(td));
  2771. td->listbox->listbox.height = 8;
  2772. td->listbox->listbox.ncols = 2;
  2773. td->listbox->listbox.percentages = snewn(2, int);
  2774. td->listbox->listbox.percentages[0] = 40;
  2775. td->listbox->listbox.percentages[1] = 60;
  2776. ctrl_columns(s, 2, 75, 25);
  2777. c = ctrl_text(s, "For selected mode, send:", HELPCTX(ssh_ttymodes));
  2778. c->column = 0;
  2779. td->setbutton = ctrl_pushbutton(s, "Set", 's',
  2780. HELPCTX(ssh_ttymodes),
  2781. ttymodes_handler, P(td));
  2782. td->setbutton->column = 1;
  2783. td->setbutton->delay_taborder = true;
  2784. ctrl_columns(s, 1, 100); /* column break */
  2785. /* Bit of a hack to get the value radio buttons and
  2786. * edit-box on the same row. */
  2787. ctrl_columns(s, 2, 75, 25);
  2788. td->valradio = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
  2789. HELPCTX(ssh_ttymodes),
  2790. ttymodes_handler, P(td),
  2791. "Auto", NO_SHORTCUT, P(NULL),
  2792. "Nothing", NO_SHORTCUT, P(NULL),
  2793. "This:", NO_SHORTCUT, P(NULL));
  2794. td->valradio->column = 0;
  2795. td->valbox = ctrl_editbox(s, NULL, NO_SHORTCUT, 100,
  2796. HELPCTX(ssh_ttymodes),
  2797. ttymodes_handler, P(td), P(NULL));
  2798. td->valbox->column = 1;
  2799. td->valbox->align_next_to = td->valradio;
  2800. ctrl_tabdelay(s, td->setbutton);
  2801. }
  2802. if (!midsession) {
  2803. /*
  2804. * The Connection/SSH/X11 panel.
  2805. */
  2806. ctrl_settitle(b, "Connection/SSH/X11",
  2807. "Options controlling SSH X11 forwarding");
  2808. s = ctrl_getset(b, "Connection/SSH/X11", "x11", "X11 forwarding");
  2809. ctrl_checkbox(s, "Enable X11 forwarding", 'e',
  2810. HELPCTX(ssh_tunnels_x11),
  2811. conf_checkbox_handler,I(CONF_x11_forward));
  2812. ctrl_editbox(s, "X display location", 'x', 50,
  2813. HELPCTX(ssh_tunnels_x11),
  2814. conf_editbox_handler, I(CONF_x11_display), ED_STR);
  2815. ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2,
  2816. HELPCTX(ssh_tunnels_x11auth),
  2817. conf_radiobutton_handler,
  2818. I(CONF_x11_auth),
  2819. "MIT-Magic-Cookie-1", I(X11_MIT),
  2820. "XDM-Authorization-1", I(X11_XDM));
  2821. }
  2822. /*
  2823. * The Tunnels panel _is_ still available in mid-session.
  2824. */
  2825. ctrl_settitle(b, "Connection/SSH/Tunnels",
  2826. "Options controlling SSH port forwarding");
  2827. s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd",
  2828. "Port forwarding");
  2829. ctrl_checkbox(s, "Local ports accept connections from other hosts",'t',
  2830. HELPCTX(ssh_tunnels_portfwd_localhost),
  2831. conf_checkbox_handler,
  2832. I(CONF_lport_acceptall));
  2833. ctrl_checkbox(s, "Remote ports do the same (SSH-2 only)", 'p',
  2834. HELPCTX(ssh_tunnels_portfwd_localhost),
  2835. conf_checkbox_handler,
  2836. I(CONF_rport_acceptall));
  2837. ctrl_columns(s, 3, 55, 20, 25);
  2838. c = ctrl_text(s, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd));
  2839. c->column = COLUMN_FIELD(0,2);
  2840. /* You want to select from the list, _then_ hit Remove. So tab order
  2841. * should be that way round. */
  2842. pfd = (struct portfwd_data *)ctrl_alloc(b,sizeof(struct portfwd_data));
  2843. pfd->rembutton = ctrl_pushbutton(s, "Remove", 'r',
  2844. HELPCTX(ssh_tunnels_portfwd),
  2845. portfwd_handler, P(pfd));
  2846. pfd->rembutton->column = 2;
  2847. pfd->rembutton->delay_taborder = true;
  2848. pfd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
  2849. HELPCTX(ssh_tunnels_portfwd),
  2850. portfwd_handler, P(pfd));
  2851. pfd->listbox->listbox.height = 3;
  2852. pfd->listbox->listbox.ncols = 2;
  2853. pfd->listbox->listbox.percentages = snewn(2, int);
  2854. pfd->listbox->listbox.percentages[0] = 20;
  2855. pfd->listbox->listbox.percentages[1] = 80;
  2856. ctrl_tabdelay(s, pfd->rembutton);
  2857. ctrl_text(s, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd));
  2858. /* You want to enter source, destination and type, _then_ hit Add.
  2859. * Again, we adjust the tab order to reflect this. */
  2860. pfd->addbutton = ctrl_pushbutton(s, "Add", 'd',
  2861. HELPCTX(ssh_tunnels_portfwd),
  2862. portfwd_handler, P(pfd));
  2863. pfd->addbutton->column = 2;
  2864. pfd->addbutton->delay_taborder = true;
  2865. pfd->sourcebox = ctrl_editbox(s, "Source port", 's', 40,
  2866. HELPCTX(ssh_tunnels_portfwd),
  2867. portfwd_handler, P(pfd), P(NULL));
  2868. pfd->sourcebox->column = 0;
  2869. pfd->destbox = ctrl_editbox(s, "Destination", 'i', 67,
  2870. HELPCTX(ssh_tunnels_portfwd),
  2871. portfwd_handler, P(pfd), P(NULL));
  2872. pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
  2873. HELPCTX(ssh_tunnels_portfwd),
  2874. portfwd_handler, P(pfd),
  2875. "Local", 'l', P(NULL),
  2876. "Remote", 'm', P(NULL),
  2877. "Dynamic", 'y', P(NULL));
  2878. #ifndef NO_IPV6
  2879. pfd->addressfamily =
  2880. ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
  2881. HELPCTX(ssh_tunnels_portfwd_ipversion),
  2882. portfwd_handler, P(pfd),
  2883. "Auto", 'u', I(ADDRTYPE_UNSPEC),
  2884. "IPv4", '4', I(ADDRTYPE_IPV4),
  2885. "IPv6", '6', I(ADDRTYPE_IPV6));
  2886. #endif
  2887. ctrl_tabdelay(s, pfd->addbutton);
  2888. ctrl_columns(s, 1, 100);
  2889. if (!midsession) {
  2890. /*
  2891. * The Connection/SSH/Bugs panels.
  2892. */
  2893. ctrl_settitle(b, "Connection/SSH/Bugs",
  2894. "Workarounds for SSH server bugs");
  2895. s = ctrl_getset(b, "Connection/SSH/Bugs", "main",
  2896. "Detection of known bugs in SSH servers");
  2897. ctrl_droplist(s, "Chokes on SSH-2 ignore messages", '2', 20,
  2898. HELPCTX(ssh_bugs_ignore2),
  2899. sshbug_handler, I(CONF_sshbug_ignore2));
  2900. ctrl_droplist(s, "Handles SSH-2 key re-exchange badly", 'k', 20,
  2901. HELPCTX(ssh_bugs_rekey2),
  2902. sshbug_handler, I(CONF_sshbug_rekey2));
  2903. ctrl_droplist(s, "Chokes on PuTTY's SSH-2 'winadj' requests", 'j',
  2904. 20, HELPCTX(ssh_bugs_winadj),
  2905. sshbug_handler, I(CONF_sshbug_winadj));
  2906. ctrl_droplist(s, "Replies to requests on closed channels", 'q', 20,
  2907. HELPCTX(ssh_bugs_chanreq),
  2908. sshbug_handler, I(CONF_sshbug_chanreq));
  2909. ctrl_droplist(s, "Ignores SSH-2 maximum packet size", 'x', 20,
  2910. HELPCTX(ssh_bugs_maxpkt2),
  2911. sshbug_handler, I(CONF_sshbug_maxpkt2));
  2912. s = ctrl_getset(b, "Connection/SSH/Bugs", "manual",
  2913. "Manually enabled workarounds");
  2914. ctrl_droplist(s, "Discards data sent before its greeting", 'd', 20,
  2915. HELPCTX(ssh_bugs_dropstart),
  2916. sshbug_handler_manual_only,
  2917. I(CONF_sshbug_dropstart));
  2918. ctrl_droplist(s, "Chokes on PuTTY's full KEXINIT", 'p', 20,
  2919. HELPCTX(ssh_bugs_filter_kexinit),
  2920. sshbug_handler_manual_only,
  2921. I(CONF_sshbug_filter_kexinit));
  2922. ctrl_settitle(b, "Connection/SSH/More bugs",
  2923. "Further workarounds for SSH server bugs");
  2924. s = ctrl_getset(b, "Connection/SSH/More bugs", "main",
  2925. "Detection of known bugs in SSH servers");
  2926. ctrl_droplist(s, "Old RSA/SHA2 cert algorithm naming", 'l', 20,
  2927. HELPCTX(ssh_bugs_rsa_sha2_cert_userauth),
  2928. sshbug_handler,
  2929. I(CONF_sshbug_rsa_sha2_cert_userauth));
  2930. ctrl_droplist(s, "Requires padding on SSH-2 RSA signatures", 'p', 20,
  2931. HELPCTX(ssh_bugs_rsapad2),
  2932. sshbug_handler, I(CONF_sshbug_rsapad2));
  2933. ctrl_droplist(s, "Only supports pre-RFC4419 SSH-2 DH GEX", 'd', 20,
  2934. HELPCTX(ssh_bugs_oldgex2),
  2935. sshbug_handler, I(CONF_sshbug_oldgex2));
  2936. ctrl_droplist(s, "Miscomputes SSH-2 HMAC keys", 'm', 20,
  2937. HELPCTX(ssh_bugs_hmac2),
  2938. sshbug_handler, I(CONF_sshbug_hmac2));
  2939. ctrl_droplist(s, "Misuses the session ID in SSH-2 PK auth", 'n', 20,
  2940. HELPCTX(ssh_bugs_pksessid2),
  2941. sshbug_handler, I(CONF_sshbug_pksessid2));
  2942. ctrl_droplist(s, "Miscomputes SSH-2 encryption keys", 'e', 20,
  2943. HELPCTX(ssh_bugs_derivekey2),
  2944. sshbug_handler, I(CONF_sshbug_derivekey2));
  2945. ctrl_droplist(s, "Chokes on SSH-1 ignore messages", 'i', 20,
  2946. HELPCTX(ssh_bugs_ignore1),
  2947. sshbug_handler, I(CONF_sshbug_ignore1));
  2948. ctrl_droplist(s, "Refuses all SSH-1 password camouflage", 's', 20,
  2949. HELPCTX(ssh_bugs_plainpw1),
  2950. sshbug_handler, I(CONF_sshbug_plainpw1));
  2951. ctrl_droplist(s, "Chokes on SSH-1 RSA authentication", 'r', 20,
  2952. HELPCTX(ssh_bugs_rsa1),
  2953. sshbug_handler, I(CONF_sshbug_rsa1));
  2954. }
  2955. }
  2956. if (DISPLAY_RECONFIGURABLE_PROTOCOL(PROT_SERIAL)) {
  2957. const BackendVtable *ser_vt = backend_vt_from_proto(PROT_SERIAL);
  2958. /*
  2959. * The Connection/Serial panel.
  2960. */
  2961. ctrl_settitle(b, "Connection/Serial",
  2962. "Options controlling local serial lines");
  2963. if (!midsession) {
  2964. /*
  2965. * We don't permit switching to a different serial port in
  2966. * midflight, although we do allow all other
  2967. * reconfiguration.
  2968. */
  2969. s = ctrl_getset(b, "Connection/Serial", "serline",
  2970. "Select a serial line");
  2971. ctrl_editbox(s, "Serial line to connect to", 'l', 40,
  2972. HELPCTX(serial_line),
  2973. conf_editbox_handler, I(CONF_serline), ED_STR);
  2974. }
  2975. s = ctrl_getset(b, "Connection/Serial", "sercfg", "Configure the serial line");
  2976. ctrl_editbox(s, "Speed (baud)", 's', 40,
  2977. HELPCTX(serial_speed),
  2978. conf_editbox_handler, I(CONF_serspeed), ED_INT);
  2979. ctrl_editbox(s, "Data bits", 'b', 40,
  2980. HELPCTX(serial_databits),
  2981. conf_editbox_handler, I(CONF_serdatabits), ED_INT);
  2982. /*
  2983. * Stop bits come in units of one half.
  2984. */
  2985. static const struct conf_editbox_handler_type conf_editbox_stopbits = {
  2986. .type = EDIT_FIXEDPOINT, .denominator = 2};
  2987. ctrl_editbox(s, "Stop bits", 't', 40,
  2988. HELPCTX(serial_stopbits),
  2989. conf_editbox_handler, I(CONF_serstopbits),
  2990. CP(&conf_editbox_stopbits));
  2991. ctrl_droplist(s, "Parity", 'p', 40,
  2992. HELPCTX(serial_parity), serial_parity_handler,
  2993. I(ser_vt->serial_parity_mask));
  2994. ctrl_droplist(s, "Flow control", 'f', 40,
  2995. HELPCTX(serial_flow), serial_flow_handler,
  2996. I(ser_vt->serial_flow_mask));
  2997. }
  2998. if (DISPLAY_RECONFIGURABLE_PROTOCOL(PROT_TELNET)) {
  2999. /*
  3000. * The Connection/Telnet panel.
  3001. */
  3002. ctrl_settitle(b, "Connection/Telnet",
  3003. "Options controlling Telnet connections");
  3004. s = ctrl_getset(b, "Connection/Telnet", "protocol",
  3005. "Telnet protocol adjustments");
  3006. if (!midsession) {
  3007. ctrl_radiobuttons(s, "Handling of OLD_ENVIRON ambiguity:",
  3008. NO_SHORTCUT, 2,
  3009. HELPCTX(telnet_oldenviron),
  3010. conf_radiobutton_bool_handler,
  3011. I(CONF_rfc_environ),
  3012. "BSD (commonplace)", 'b', I(false),
  3013. "RFC 1408 (unusual)", 'f', I(true));
  3014. ctrl_radiobuttons(s, "Telnet negotiation mode:", 't', 2,
  3015. HELPCTX(telnet_passive),
  3016. conf_radiobutton_bool_handler,
  3017. I(CONF_passive_telnet),
  3018. "Passive", I(true), "Active", I(false));
  3019. }
  3020. ctrl_checkbox(s, "Keyboard sends Telnet special commands", 'k',
  3021. HELPCTX(telnet_specialkeys),
  3022. conf_checkbox_handler,
  3023. I(CONF_telnet_keyboard));
  3024. ctrl_checkbox(s, "Return key sends Telnet New Line instead of ^M",
  3025. 'm', HELPCTX(telnet_newline),
  3026. conf_checkbox_handler,
  3027. I(CONF_telnet_newline));
  3028. }
  3029. if (DISPLAY_NON_RECONFIGURABLE_PROTOCOL(PROT_RLOGIN)) {
  3030. /*
  3031. * The Connection/Rlogin panel.
  3032. */
  3033. ctrl_settitle(b, "Connection/Rlogin",
  3034. "Options controlling Rlogin connections");
  3035. s = ctrl_getset(b, "Connection/Rlogin", "data",
  3036. "Data to send to the server");
  3037. ctrl_editbox(s, "Local username:", 'l', 50,
  3038. HELPCTX(rlogin_localuser),
  3039. conf_editbox_handler, I(CONF_localusername), ED_STR);
  3040. }
  3041. if (DISPLAY_NON_RECONFIGURABLE_PROTOCOL(PROT_SUPDUP)) {
  3042. /*
  3043. * The Connection/SUPDUP panel.
  3044. */
  3045. ctrl_settitle(b, "Connection/SUPDUP",
  3046. "Options controlling SUPDUP connections");
  3047. s = ctrl_getset(b, "Connection/SUPDUP", "main", NULL);
  3048. ctrl_editbox(s, "Location string", 'l', 70,
  3049. HELPCTX(supdup_location),
  3050. conf_editbox_handler, I(CONF_supdup_location),
  3051. ED_STR);
  3052. ctrl_radiobuttons(s, "Extended ASCII Character set:", 'e', 4,
  3053. HELPCTX(supdup_ascii),
  3054. conf_radiobutton_handler,
  3055. I(CONF_supdup_ascii_set),
  3056. "None", I(SUPDUP_CHARSET_ASCII),
  3057. "ITS", I(SUPDUP_CHARSET_ITS),
  3058. "WAITS", I(SUPDUP_CHARSET_WAITS));
  3059. ctrl_checkbox(s, "**MORE** processing", 'm',
  3060. HELPCTX(supdup_more),
  3061. conf_checkbox_handler,
  3062. I(CONF_supdup_more));
  3063. ctrl_checkbox(s, "Terminal scrolling", 's',
  3064. HELPCTX(supdup_scroll),
  3065. conf_checkbox_handler,
  3066. I(CONF_supdup_scroll));
  3067. }
  3068. }