AmendHub

Download

jcs

/

wifi_da

/

window.c

 

(View History)

jcs   *: Don't rely on our static wifi_da persisting Latest amendment: 40 on 2025-01-07

1 /*
2 * Copyright (c) 2023 joshua stein <jcs@jcs.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include <stdio.h>
18 #include <string.h>
19 #include "wi-fi.h"
20
21 short nwifi_scan_networks = 0;
22 struct wifi_network_entry wifi_menu_networks[MAX_WIFI_NETWORKS];
23 short nwifi_menu_networks = 0;
24
25 void create_logger(void);
26 pascal Boolean WiFiPasswordDialogFieldFilter(DialogPtr dlg,
27 EventRecord *event, short *hit);
28
29 void
30 create_window(short ctlrefnum)
31 {
32 Str255 str;
33 GrafPtr savePort, tport;
34
35 memset(&wifi_menu_networks, 0, sizeof(wifi_menu_networks));
36 wifi_da.str_res_id = find_str_res_id();
37
38 GetPort(&savePort);
39
40 /* screenBits is not available from a DA */
41 tport = (GrafPtr)NewPtr(sizeof(GrafPort));
42 OpenPort(tport);
43 /* upper right corner, but leave space for desktop icon */
44 wifi_da.bounds.top = 45;
45 wifi_da.bounds.bottom = wifi_da.bounds.top + DA_HEIGHT;
46 wifi_da.bounds.left = tport->portRect.right - DA_WIDTH - 70;
47 wifi_da.bounds.right = wifi_da.bounds.left + DA_WIDTH;
48 ClosePort(tport);
49
50 wifi_da.win = NewWindow(0L, &wifi_da.bounds, "\pWi-Fi", true,
51 rDocProc, 0L, true, 0L);
52 ((WindowPeek)(wifi_da.win))->windowKind = ctlrefnum;
53
54 wifi_da.win_shadow.rowBytes = (((DA_WIDTH - 1) / 16) + 1) * 2;
55 wifi_da.win_shadow.baseAddr =
56 xmalloczero(wifi_da.win_shadow.rowBytes * DA_HEIGHT);
57 SetRect(&wifi_da.win_shadow.bounds, 0, 0, DA_WIDTH, DA_HEIGHT);
58
59 wifi_da.signal_icons = (SICNHandle)GetResource('SICN',
60 OwnedResourceID(0));
61 if (wifi_da.signal_icons == NULL)
62 panic("Can't find SICN");
63
64 SetRect(&wifi_da.icon_rect, 6, 4, 22, 20); /* ltrb */
65
66 wifi_da.ssid_menu = NewMenu(OwnedResourceID(10), "\p");
67 GetIndString(str, wifi_da.str_res_id, STR_FINDING_WIFI_ID);
68 InsMenuItem(wifi_da.ssid_menu, str, 1);
69
70 SetRect(&wifi_da.ssid_menu_rect, 30, 3, 170, 21); /* ltrb */
71
72 #if 0 /* system 6 does not seem to support popupMenuProc */
73 ssid_list = NewControl(wifi_da.win, &wifi_da.ssid_menu_rect, 0, true,
74 0, OwnedResourceID(SSID_MENU_ID), 0, popupMenuProc + popupFixedWidth,
75 0L);
76 #endif
77
78 update_window(true);
79
80 if (wifi_scsi_id == WIFI_SCSI_ID_FINDING)
81 wifi_scsi_id = scsi_find_wifi();
82
83 if (wifi_scsi_id == WIFI_SCSI_ID_NONE) {
84 wifi_da.state = STATE_IDLE;
85 GetIndString(str, wifi_da.str_res_id, STR_NO_DEVICE_FOUND_ID);
86 SetItem(wifi_da.ssid_menu, 1, str);
87 update_window(true);
88 } else {
89 scsi_wifi_info(wifi_scsi_id, &wifi_cur_info);
90 wifi_da.state = STATE_SCANNING;
91 scsi_wifi_scan(wifi_scsi_id);
92 }
93
94 SetPort(savePort);
95 }
96
97 void
98 create_logger(void)
99 {
100 Str255 str;
101 Rect bounds;
102
103 bounds.top = 150;
104 bounds.bottom = 320;
105 bounds.left = 20;
106 bounds.right = 400;
107 GetIndString(str, wifi_da.str_res_id, STR_DEBUG_LOGS_ID);
108 wifi_da.logger = NewWindow(0L, &bounds, str, true, rDocProc, 0L,
109 false, 0L);
110 ((WindowPeek)wifi_da.logger)->windowKind = dce->dCtlRefNum;
111 }
112
113 void
114 update_window(bool force)
115 {
116 Str255 menuText;
117 GrafPtr savePort;
118 Point p;
119 short i, icon, x, w;
120 RgnHandle tmpRgn;
121 Rect r, destRect;
122 BitMap bm, cur_bits;
123
124 GetPort(&savePort);
125 SetPort(wifi_da.win);
126
127 //logger_printf("redrawing window");
128 cur_bits = wifi_da.win->portBits;
129 SetPortBits(&wifi_da.win_shadow);
130
131 if (!force)
132 BeginUpdate(wifi_da.win);
133
134 EraseRect(&wifi_da.win->portRect);
135 DrawControls(wifi_da.win);
136
137 /* system 6 does not seem to support popupMenuProc, fake it */
138 FrameRect(&wifi_da.ssid_menu_rect);
139 MoveTo(wifi_da.ssid_menu_rect.left + 1, wifi_da.ssid_menu_rect.bottom);
140 LineTo(wifi_da.ssid_menu_rect.right, wifi_da.ssid_menu_rect.bottom);
141 MoveTo(wifi_da.ssid_menu_rect.right, wifi_da.ssid_menu_rect.top + 1);
142 LineTo(wifi_da.ssid_menu_rect.right, wifi_da.ssid_menu_rect.bottom);
143
144 TextFont(systemFont);
145 TextSize(0);
146 GetItem(wifi_da.ssid_menu, 1, &menuText);
147 x = 15;
148 MoveTo(wifi_da.ssid_menu_rect.left + x, 16);
149
150 for (i = 1; i <= menuText[0]; i++) {
151 w = CharWidth(menuText[i]);
152 if (i < menuText[0] && x + w >= (wifi_da.ssid_menu_rect.right -
153 wifi_da.ssid_menu_rect.left - 14)) {
154 /* truncate */
155 GetPen(&p);
156 MoveTo(p.h - 1, p.v);
157 DrawChar('…');
158 break;
159 }
160 DrawChar(menuText[i]);
161 x += w;
162 }
163
164 HLock(wifi_da.signal_icons);
165
166 if (wifi_scsi_id == WIFI_SCSI_ID_NONE)
167 icon = SIGNAL_NO_DEVICE;
168 else if (wifi_scsi_id == WIFI_SCSI_ID_FINDING)
169 icon = SIGNAL_FINDING_DEVICE;
170 else if (wifi_cur_info.ssid[0] == '\0')
171 icon = SIGNAL_NONE;
172 else if (wifi_cur_info.rssi >= -60)
173 icon = SIGNAL_4;
174 else if (wifi_cur_info.rssi >= -70)
175 icon = SIGNAL_3;
176 else if (wifi_cur_info.rssi >= -75)
177 icon = SIGNAL_2;
178 else
179 icon = SIGNAL_1;
180
181 bm.baseAddr = (Ptr)(*(wifi_da.signal_icons))[icon];
182 bm.rowBytes = 2;
183 SetRect(&bm.bounds, 0, 0, 16, 16);
184 CopyBits(&bm, &wifi_da.win->portBits, &bm.bounds, &wifi_da.icon_rect,
185 srcOr, NULL);
186
187 HUnlock(wifi_da.signal_icons);
188
189 if (!force)
190 EndUpdate(wifi_da.win);
191
192 SetPortBits(&cur_bits);
193
194 CopyBits(&wifi_da.win_shadow, &wifi_da.win->portBits,
195 &wifi_da.win_shadow.bounds, &wifi_da.win_shadow.bounds, srcCopy, nil);
196
197 ValidRect(&wifi_da.win->portRect);
198 SetPort(savePort);
199 }
200
201 void
202 update_wifi_cur_info(void)
203 {
204 struct wifi_network_entry old_info;
205
206 if (wifi_scsi_id == WIFI_SCSI_ID_NONE)
207 return;
208
209 memcpy(&old_info, &wifi_cur_info, sizeof(old_info));
210
211 scsi_wifi_info(wifi_scsi_id, &wifi_cur_info);
212
213 if (memcmp(&old_info, &wifi_cur_info, sizeof(old_info)) != 0) {
214 if (memcmp(&old_info.ssid, &wifi_cur_info.ssid,
215 sizeof(old_info.ssid)) == 0) {
216 /* just updating RSSI */
217 logger_printf("update_wifi_cur_info: just updating rssi to %d",
218 wifi_cur_info.rssi);
219 update_window(true);
220 } else {
221 logger_printf("update_wifi_cur_info: updating ssid list");
222 update_wifi_ssid_list(false);
223 }
224 }
225 }
226
227 void
228 update_wifi_ssid_list(bool update_networks)
229 {
230 Str255 str;
231 char ssid[64];
232 short n, m, mitem;
233
234 if (wifi_scsi_id == WIFI_SCSI_ID_NONE)
235 return;
236
237 if (update_networks) {
238 nwifi_scan_networks = scsi_wifi_scan_results(wifi_scsi_id,
239 wifi_scan_networks, nitems(wifi_scan_networks));
240 logger_printf("scsi_wifi_scan_results: %d networks",
241 nwifi_scan_networks);
242
243 if (nwifi_scan_networks == 0)
244 logger_printf("no networks found during scan");
245 }
246
247 if (nwifi_scan_networks == 0) {
248 /* use our current network (or none) as the only one found */
249 memcpy(&wifi_scan_networks, &wifi_cur_info, sizeof(wifi_cur_info));
250 nwifi_scan_networks = 1;
251 }
252
253 logger_printf("current ssid: %s", wifi_cur_info.ssid[0] == '\0' ?
254 "(none)" : wifi_cur_info.ssid);
255
256 /*
257 * now start building the ssid menu from wifi_scan_networks
258 */
259
260 /* leave room for current network and trailing "(other network)" */
261 if (nwifi_scan_networks > MAX_WIFI_NETWORKS - 2) {
262 nwifi_scan_networks = MAX_WIFI_NETWORKS - 2;
263 logger_printf("capping wifi_scan_networks to %d",
264 nwifi_scan_networks);
265 }
266
267 /* put the current network (if any) first in the menu */
268 logger_printf("menu[0]: %s", wifi_cur_info.ssid[0] ?
269 wifi_cur_info.ssid : "(no network)");
270 memcpy(&wifi_menu_networks[0], &wifi_cur_info,
271 sizeof(wifi_menu_networks[0]));
272 nwifi_menu_networks = 1;
273
274 /* add each additional network from the scan */
275 for (n = 0; n < nwifi_scan_networks; n++) {
276 /* except current one, which we added first */
277 if (strcmp(wifi_scan_networks[n].ssid, wifi_cur_info.ssid) == 0)
278 continue;
279
280 memcpy(&wifi_menu_networks[nwifi_menu_networks],
281 &wifi_scan_networks[n], sizeof(wifi_menu_networks[0]));
282 logger_printf("menu[%d]: %s", nwifi_menu_networks,
283 wifi_menu_networks[nwifi_menu_networks].ssid);
284 nwifi_menu_networks++;
285 }
286
287 if (wifi_menu_networks[0].ssid[0] == '\0') {
288 /* replace blank string with "(no network)" */
289 GetIndString(str, wifi_da.str_res_id, STR_NO_NETWORK_ID);
290 PtoCstr(str);
291 strlcpy(wifi_menu_networks[0].ssid, (char *)str,
292 sizeof(wifi_menu_networks[0].ssid));
293 }
294
295 /* add "other network" as last entry */
296 nwifi_menu_networks++;
297 if (nwifi_menu_networks > MAX_WIFI_NETWORKS)
298 panic("nwifi_menu_networks overflow");
299 GetIndString(str, wifi_da.str_res_id, STR_OTHER_NETWORK_ID);
300 PtoCstr(str);
301 strlcpy(wifi_menu_networks[nwifi_menu_networks - 1].ssid,
302 (char *)str, sizeof(wifi_menu_networks[0].ssid));
303 wifi_menu_networks[nwifi_menu_networks - 1].flags =
304 WIFI_NETWORK_FLAG_AUTH | WIFI_NETWORK_FLAG_HIDDEN;
305 logger_printf("menu[%d]: %s", nwifi_menu_networks - 1,
306 "(other network)");
307
308 /*
309 * leave the first item and we'll set its text later but delete all
310 * others
311 */
312 while (CountMItems(wifi_da.ssid_menu) > 1)
313 DelMenuItem(wifi_da.ssid_menu, 2);
314
315 for (n = 0, mitem = 1; n < nwifi_menu_networks; n++) {
316 /*
317 * InsMenuItem supports meta chars in item text which can
318 * have side effects, so insert a blank item and then set its
319 * name with SetItem which does not suport meta chars.
320 */
321 strlcpy(ssid, wifi_menu_networks[n].ssid, sizeof(ssid));
322 CtoPstr(ssid);
323
324 if (n > 0)
325 InsMenuItem(wifi_da.ssid_menu, "\p...", mitem);
326
327 SetItem(wifi_da.ssid_menu, mitem, ssid);
328
329 if (wifi_cur_info.ssid[0] == '\0' && n == 0)
330 CheckItem(wifi_da.ssid_menu, mitem, true);
331 else
332 CheckItem(wifi_da.ssid_menu, mitem,
333 (strcmp(wifi_menu_networks[n].ssid,
334 wifi_cur_info.ssid) == 0));
335
336 mitem++;
337 }
338
339 update_window(true);
340 }
341
342 void
343 activate_window(bool activate)
344 {
345 Rect r;
346 GrafPtr savePort;
347
348 #if 0
349 GetPort(&savePort);
350 SetPort(win);
351 r = win->portRect;
352 r.top = r.bottom - 16;
353 r.left = r.left - 16;
354 InvalRect(&r);
355 SetPort(savePort);
356 #endif
357 }
358
359 void
360 destroy_windows(void)
361 {
362 ReleaseResource(wifi_da.signal_icons);
363
364 if (wifi_da.win) {
365 DisposeWindow(wifi_da.win);
366 wifi_da.win = 0;
367 }
368
369 if (wifi_da.logger) {
370 DisposeWindow(wifi_da.logger);
371 wifi_da.logger = 0;
372 }
373 }
374
375 void
376 window_mousedown(Point p)
377 {
378 Str255 str, password, ssid;
379 Rect menu_r, icon_r, r, irect;
380 GrafPtr savePort;
381 short mitems, n, selitem, hit, itype;
382 long new_net;
383 struct wifi_network_entry *net;
384 struct wifi_join_request wjr;
385 DialogPtr dg;
386 ControlHandle ihandle;
387
388 GetPort(&savePort);
389 SetPort(wifi_da.win);
390
391 icon_r = wifi_da.icon_rect;
392 LocalToGlobal(&icon_r);
393
394 /* XXX: why does PtInRect not work? */
395
396 if (p.h >= icon_r.left && p.h <= icon_r.left + icon_r.right &&
397 p.v >= icon_r.top && p.v <= icon_r.top + icon_r.bottom) {
398 if (wifi_da.logger) {
399 DisposeWindow(wifi_da.logger);
400 wifi_da.logger = 0;
401 } else
402 create_logger();
403 return;
404 }
405
406 menu_r = wifi_da.ssid_menu_rect;
407 LocalToGlobal(&menu_r);
408
409 if (!(p.h >= menu_r.left && p.h <= menu_r.left + menu_r.right &&
410 p.v >= menu_r.top && p.v <= menu_r.top + menu_r.bottom)) {
411 SetPort(savePort);
412 return;
413 }
414
415 if (wifi_scsi_id == WIFI_SCSI_ID_NONE)
416 return;
417
418 InsertMenu(wifi_da.ssid_menu, -1);
419
420 mitems = CountMItems(wifi_da.ssid_menu);
421 selitem = 1;
422 for (n = 0; n < mitems; n++) {
423 if (strcmp(wifi_menu_networks[n].ssid, wifi_cur_info.ssid) == 0) {
424 selitem = n + 1;
425 break;
426 }
427 }
428
429 new_net = PopUpMenuSelect(wifi_da.ssid_menu, menu_r.top + 1,
430 menu_r.left + 1, selitem);
431
432 DeleteMenu((*(wifi_da.ssid_menu))->menuID);
433 if (hiword(new_net) == 0 || loword(new_net) == selitem ||
434 loword(new_net) > nwifi_menu_networks)
435 goto menu_done;
436 net = &wifi_menu_networks[loword(new_net) - 1];
437 logger_printf("clicked %s (item %d)",
438 wifi_menu_networks[loword(new_net) - 1].ssid, loword(new_net));
439
440 memset(&wjr, 0, sizeof(wjr));
441
442 if (net->flags & WIFI_NETWORK_FLAG_HIDDEN) {
443 dg = GetNewDialog(OwnedResourceID(PROMPT_DIALOG_ID), 0L,
444 (WindowPtr)-1L);
445 center_in_screen(((DialogPeek)dg)->window.port.portRect.right,
446 ((DialogPeek)dg)->window.port.portRect.bottom, false, &r);
447 MoveWindow(dg, r.left, r.top, false);
448
449 GetIndString(str, wifi_da.str_res_id, STR_SSID_DIALOG_TITLE_ID);
450 SetWTitle(dg, str);
451
452 /* continue button */
453 GetDItem(dg, ok, &itype, &ihandle, &irect);
454 GetIndString(str, wifi_da.str_res_id, STR_CONTINUE_ID);
455 SetCTitle(ihandle, str);
456
457 /* cancel button */
458 GetDItem(dg, cancel, &itype, &ihandle, &irect);
459 GetIndString(str, wifi_da.str_res_id, STR_CANCEL_ID);
460 SetCTitle(ihandle, str);
461
462 /* "SSID:" */
463 GetDItem(dg, PROMPT_DIALOG_INPUT_LABEL_ID, &itype, &ihandle,
464 &irect);
465 GetIndString(str, wifi_da.str_res_id, STR_SSID_ID);
466 SetIText(ihandle, str);
467
468 /* "Enter the Wi-Fi network SSID:" */
469 GetDItem(dg, PROMPT_DIALOG_TITLE_LABEL_ID, &itype, &ihandle,
470 &irect);
471 GetIndString(str, wifi_da.str_res_id, STR_ENTER_SSID_ID);
472 SetIText(ihandle, str);
473
474 ShowWindow(dg);
475 SetPort(dg);
476
477 /* outline continue button */
478 GetDItem(dg, ok, &itype, &ihandle, &irect);
479 PenSize(3, 3);
480 InsetRect(&irect, -4, -4);
481 FrameRoundRect(&irect, 16, 16);
482 PenNormal();
483
484 for (;;) {
485 ModalDialog(ModalDialogFilter, &hit);
486 if (hit == ok || hit == cancel)
487 break;
488 }
489
490 if (hit != ok) {
491 DisposDialog(dg);
492 goto menu_done;
493 }
494
495 GetDItem(dg, PROMPT_DIALOG_INPUT_FIELD_ID, &itype, &ihandle,
496 &irect);
497 GetIText(ihandle, &ssid);
498 PtoCstr(ssid);
499 strlcpy(wjr.ssid, (char *)ssid, sizeof(wjr.ssid));
500
501 DisposDialog(dg);
502 } else
503 strlcpy(wjr.ssid, net->ssid, sizeof(wjr.ssid));
504
505 if (net->flags & WIFI_NETWORK_FLAG_AUTH) {
506 dg = GetNewDialog(OwnedResourceID(PROMPT_DIALOG_ID), 0L,
507 (WindowPtr)-1L);
508 center_in_screen(((DialogPeek)dg)->window.port.portRect.right,
509 ((DialogPeek)dg)->window.port.portRect.bottom, false, &r);
510 MoveWindow(dg, r.left, r.top, false);
511
512 GetIndString(str, wifi_da.str_res_id, STR_PASSWORD_DIALOG_TITLE_ID);
513 SetWTitle(dg, str);
514
515 /* continue button */
516 GetDItem(dg, ok, &itype, &ihandle, &irect);
517 GetIndString(str, wifi_da.str_res_id, STR_CONTINUE_ID);
518 SetCTitle(ihandle, str);
519
520 /* cancel button */
521 GetDItem(dg, cancel, &itype, &ihandle, &irect);
522 GetIndString(str, wifi_da.str_res_id, STR_CANCEL_ID);
523 SetCTitle(ihandle, str);
524
525 /* "Password:" */
526 GetDItem(dg, PROMPT_DIALOG_INPUT_LABEL_ID, &itype, &ihandle,
527 &irect);
528 GetIndString(str, wifi_da.str_res_id, STR_PASSWORD_ID);
529 SetIText(ihandle, str);
530
531 /* "\"^0\" requires a password:" */
532 GetDItem(dg, PROMPT_DIALOG_TITLE_LABEL_ID, &itype, &ihandle,
533 &irect);
534 GetIndString(str, wifi_da.str_res_id, STR_REQUIRES_PASSWORD_ID);
535 SetIText(ihandle, str);
536
537 strlcpy((char *)ssid, wjr.ssid, sizeof(ssid));
538 CtoPstr(ssid);
539 ParamText(ssid, "\p", "\p", "\p");
540
541 ShowWindow(dg);
542 SetPort(dg);
543
544 GetDItem(dg, PROMPT_DIALOG_PASSWORD_STORAGE_ID, &itype, &ihandle,
545 &irect);
546 SetIText(ihandle, "\p");
547
548 /* outline ok button */
549 GetDItem(dg, ok, &itype, &ihandle, &irect);
550 PenSize(3, 3);
551 InsetRect(&irect, -4, -4);
552 FrameRoundRect(&irect, 16, 16);
553 PenNormal();
554
555 for (;;) {
556 ModalDialog(WiFiPasswordDialogFieldFilter, &hit);
557 if (hit == ok || hit == cancel)
558 break;
559 }
560
561 if (hit != ok) {
562 DisposDialog(dg);
563 goto menu_done;
564 }
565
566 GetDItem(dg, PROMPT_DIALOG_PASSWORD_STORAGE_ID, &itype, &ihandle,
567 &irect);
568 GetIText(ihandle, &password);
569 PtoCstr(password);
570 //DEBUG_LOG(("pass is \"%s\"", password));
571 strlcpy(wjr.key, (char *)password, sizeof(wjr.key));
572
573 DisposDialog(dg);
574 } else
575 logger_printf("network %s does not have auth rssi:%d channel:%d flags:0x%x",
576 net->ssid, (short)net->rssi, (short)net->channel, (short)net->flags);
577
578 scsi_wifi_join(wifi_scsi_id, &wjr);
579
580 /* force an update of the list */
581 scsi_wifi_info(wifi_scsi_id, &wifi_cur_info);
582 update_wifi_ssid_list(false);
583
584 menu_done:
585 SetPort(savePort);
586 }
587
588 pascal Boolean
589 WiFiPasswordDialogFieldFilter(DialogPtr dlg, EventRecord *event,
590 short *hit)
591 {
592 Str255 password;
593 DialogPeek dlgp;
594 ControlHandle ihandle;
595 Rect irect;
596 short sel_start, sel_end, itype;
597 char key;
598
599 dlgp = (DialogPeek)dlg;
600
601 switch (event->what) {
602 case keyDown:
603 case autoKey:
604 sel_start = (*(dlgp->textH))->selStart;
605 sel_end = (*(dlgp->textH))->selEnd;
606
607 key = event->message & charCodeMask;
608 if (event->modifiers & cmdKey) {
609 /* TODO: implement DlgPaste for cmd+v? */
610 event->what = nullEvent;
611 return FALSE;
612 }
613
614 GetDItem(dlg, PROMPT_DIALOG_PASSWORD_STORAGE_ID, &itype,
615 &ihandle, &irect);
616 GetIText(ihandle, &password);
617 PtoCstr(password);
618
619 if (key == 8) {
620 /* backspace */
621 if (sel_start == sel_end && sel_start > 0)
622 memmove(password + sel_start - 1, password + sel_start,
623 sizeof(password) - sel_start - 1);
624 else if (sel_start != sel_end)
625 memmove(password + sel_start, password + sel_end,
626 sizeof(password) - sel_end - 1);
627 } else if (sel_start >= sizeof(password)) {
628 event->what = nullEvent;
629 return FALSE;
630 } else if (key >= ' ' && key <= '~') {
631 if (sel_start != sel_end)
632 /* delete selection before making space for new char */
633 memmove(password + sel_start, password + sel_end,
634 sizeof(password) - sel_end - 1);
635 memmove(password + sel_start + 1, password + sel_start,
636 sizeof(password) - sel_start - 1);
637 password[sel_start] = key;
638 event->message = '•';
639 }
640 password[(*(dlgp->textH))->teLength + 1] = '\0';
641 CtoPstr(password);
642
643 SetIText(ihandle, password);
644 sel_start = 0;
645 break;
646 }
647
648 return ModalDialogFilter(dlg, event, hit);
649 }