config.c 129 KB

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