jcs
/wallops
/amendments
/13
irc: Support IRC server passwords for automatic NickServ identification
This was much harder than it needed to be because there is no
way to have password fields in a dialog box. We are now faking it by
intercepting keystrokes on such fields and manipulating a char array
behind the scenes while just passing • characters to the TextEdit
control.
jcs made amendment 13 over 2 years ago
--- chatter.c Sun Feb 6 19:30:43 2022
+++ chatter.c Mon Feb 7 16:51:10 2022
@@ -35,8 +35,8 @@ void chatter_atexit(struct focusable *focusable);
void
chatter_init(const char *server, const unsigned short port,
- const char *nick, const char *ident, const char *realname,
- const char *channel)
+ const char *password, const char *nick, const char *ident,
+ const char *realname, const char *channel)
{
struct focusable *focusable;
struct chatter *chatter;
@@ -51,10 +51,13 @@ chatter_init(const char *server, const unsigned short
chatter->irc_state = IRC_STATE_UNINITED;
chatter->irc_hostname = xstrdup(server);
chatter->irc_port = port;
+ if (password && password[0])
+ chatter->irc_password = xstrdup(password);
chatter->irc_nick = xstrdup(nick);
chatter->irc_ident = xstrdup(ident);
chatter->irc_realname = xstrdup(realname);
- chatter->irc_channel_autojoin = xstrdup(channel);
+ if (channel && channel[0])
+ chatter->irc_channel_autojoin = xstrdup(channel);
bounds.left = padding;
bounds.top = screenBits.bounds.top + padding +
--- chatter.h Sun Feb 6 19:37:55 2022
+++ chatter.h Mon Feb 7 12:57:14 2022
@@ -47,10 +47,11 @@
#define CONNECT_DLOG_ID 129
#define CONNECT_SERVER_ID 2
#define CONNECT_PORT_ID 3
-#define CONNECT_NICK_ID 4
-#define CONNECT_IDENT_ID 5
-#define CONNECT_REALNAME_ID 6
-#define CONNECT_CHANNEL_ID 7
+#define CONNECT_PASSWORD_ID 4
+#define CONNECT_NICK_ID 5
+#define CONNECT_IDENT_ID 6
+#define CONNECT_REALNAME_ID 7
+#define CONNECT_CHANNEL_ID 8
#define STR_SERVER_ID 1000
#define STR_PORT_ID 1001
@@ -58,6 +59,7 @@
#define STR_IDENT_ID 1003
#define STR_REALNAME_ID 1004
#define STR_CHANNEL_ID 1005
+#define STR_PASSWORD_ID 1006
#define DEFAULT_SERVER_NAME "irc.libera.chat"
#define DEFAULT_PORT "6667"
@@ -93,6 +95,7 @@ struct chatter {
short irc_state;
char *irc_hostname;
short irc_port;
+ char *irc_password;
char *irc_nick;
char *irc_ident;
char *irc_realname;
@@ -121,8 +124,8 @@ void close_focusable(struct focusable *focusable);
void hide_focusable(struct focusable *focusable);
void chatter_init(const char *server, const unsigned short port,
- const char *nick, const char *ident, const char *realname,
- const char *channel);
+ const char *nick, const char *password, const char *ident,
+ const char *realname, const char *channel);
void chatter_update_titlebar(struct chatter *chatter);
size_t chatter_printf(struct chatter *chatter, const char *format, ...);
void chatter_sync_nick_list(struct chatter *chatter, bool initial_sync);
--- irc.c Sun Feb 6 20:17:09 2022
+++ irc.c Mon Feb 7 16:52:11 2022
@@ -276,6 +276,12 @@ irc_login(struct chatter *chatter)
if (!irc_can_send(chatter))
return;
+ if (chatter->irc_password && chatter->irc_password[0]) {
+ len = snprintf(chatter->irc_line, sizeof(chatter->irc_line),
+ "PASS %s\r\n", chatter->irc_password);
+ irc_send(chatter, chatter->irc_line, len);
+ }
+
len = snprintf(chatter->irc_line, sizeof(chatter->irc_line),
"NICK %s\r\n", chatter->irc_nick);
irc_send(chatter, chatter->irc_line, len);
@@ -284,7 +290,7 @@ irc_login(struct chatter *chatter)
"USER %s 8 * :%s\r\n", chatter->irc_ident, chatter->irc_realname);
irc_send(chatter, chatter->irc_line, len);
- if (chatter->irc_channel_autojoin) {
+ if (chatter->irc_channel_autojoin && chatter->irc_channel_autojoin[0]) {
len = snprintf(chatter->irc_line, sizeof(chatter->irc_line),
"JOIN %s\r\n", chatter->irc_channel_autojoin);
irc_send(chatter, chatter->irc_line, len);
--- main.c Sun Feb 6 20:21:15 2022
+++ main.c Mon Feb 7 16:49:02 2022
@@ -27,7 +27,8 @@ NMRec notification = { 0 };
enum {
CONFIG_TYPE_STRING,
- CONFIG_TYPE_SHORT
+ CONFIG_TYPE_SHORT,
+ CONFIG_TYPE_PASSWORD
};
struct config_field {
@@ -38,11 +39,14 @@ struct config_field {
short ditl_id;
short res_id;
char sdefault[32];
+ char password_storage[256];
} config_fields[] = {
{ "Server Name", CONFIG_TYPE_STRING, 1, 0,
CONNECT_SERVER_ID, STR_SERVER_ID, DEFAULT_SERVER_NAME },
{ "Server Port", CONFIG_TYPE_SHORT, 1, 65535,
CONNECT_PORT_ID, STR_PORT_ID, DEFAULT_PORT },
+ { "Server Password", CONFIG_TYPE_PASSWORD, 0, 0,
+ CONNECT_PASSWORD_ID, STR_PASSWORD_ID, "" },
{ "Nickname", CONFIG_TYPE_STRING, 1, 0,
CONNECT_NICK_ID, STR_NICK_ID, "" },
{ "Ident", CONFIG_TYPE_STRING, 1, 0,
@@ -202,12 +206,12 @@ main(void)
short
show_connect_dialog(void)
{
- Str255 txt, server, ports, nick, ident, realname, channel;
+ Str255 txt, server, ports, nick, ident, realname, channel, password;
StringHandle h;
DialogPtr dlg;
Handle ihandle;
Rect irect;
- size_t size, n;
+ size_t size, n, m;
long port;
short hit, itype, ret;
@@ -220,9 +224,25 @@ show_connect_dialog(void)
GetDItem(dlg, cf->ditl_id, &itype, &ihandle, &irect);
+ if (cf->type == CONFIG_TYPE_PASSWORD) {
+ PasswordDialogFieldFilterSetup(cf->ditl_id,
+ cf->password_storage, sizeof(cf->password_storage));
+ }
+
if (cf->res_id && (h = GetString(cf->res_id))) {
HLock(h);
- SetIText(ihandle, *h);
+ if (cf->type == CONFIG_TYPE_PASSWORD) {
+ size = (*h)[0];
+ for (m = 0; m < size; m++)
+ cf->password_storage[m] = '•';
+ cf->password_storage[m] = '\0';
+ CtoPstr(cf->password_storage);
+ SetIText(ihandle, cf->password_storage);
+ strlcpy(cf->password_storage, PtoCstr(*h),
+ sizeof(cf->password_storage));
+ } else {
+ SetIText(ihandle, *h);
+ }
HUnlock(h);
ReleaseResource(h);
} else if (cf->sdefault[0] != '\0') {
@@ -235,7 +255,7 @@ show_connect_dialog(void)
ShowWindow(dlg);
get_input:
- ModalDialog(ModalDialogFilter, &hit);
+ ModalDialog(PasswordDialogFieldFilter, &hit);
switch (hit) {
case -1:
DisposeDialog(dlg);
@@ -252,12 +272,17 @@ verify:
long lval;
short sval;
- GetDItem(dlg, cf->ditl_id, &itype, &ihandle, &irect);
- GetIText(ihandle, txt);
- PtoCstr(txt);
-
+ if (cf->type == CONFIG_TYPE_PASSWORD) {
+ memcpy((char *)&txt, cf->password_storage, sizeof(txt));
+ } else {
+ GetDItem(dlg, cf->ditl_id, &itype, &ihandle, &irect);
+ GetIText(ihandle, txt);
+ PtoCstr(txt);
+ }
+
switch (cf->type) {
case CONFIG_TYPE_STRING:
+ case CONFIG_TYPE_PASSWORD:
if (cf->min && strlen((char *)txt) < cf->min) {
warn("%s is too short (minimum %d)", cf->name, cf->min);
goto get_input;
@@ -287,6 +312,9 @@ verify:
case CONNECT_PORT_ID:
port = atol((char *)txt);
break;
+ case CONNECT_PASSWORD_ID:
+ strlcpy((char *)&password, (char *)txt, sizeof(password));
+ break;
case CONNECT_NICK_ID:
strlcpy((char *)&nick, (char *)txt, sizeof(nick));
break;
@@ -315,10 +343,11 @@ verify:
ReleaseResource(h);
}
+ PasswordDialogFieldFinish();
DisposeDialog(dlg);
-
- chatter_init((char *)&server, port, (char *)&nick, (char *)&ident,
- (char *)&realname, (char *)&channel);
+
+ chatter_init((char *)&server, port, (char *)&password, (char *)&nick,
+ (char *)&ident, (char *)&realname, (char *)&channel);
}
bool
@@ -450,7 +479,12 @@ close_focusable(struct focusable *focusable)
}
nfocusables--;
- focusables = xreallocarray(focusables, sizeof(Ptr), nfocusables);
+ if (nfocusables)
+ focusables = xreallocarray(focusables, sizeof(Ptr), nfocusables);
+ else {
+ free(focusables);
+ focusables = NULL;
+ }
if (nfocusables && focusables[0]->visible)
SelectWindow(focusables[0]->win);
--- util.c Thu Feb 3 16:34:58 2022
+++ util.c Mon Feb 7 16:06:20 2022
@@ -19,6 +19,8 @@
#include <stdlib.h>
#include <string.h>
#include <GestaltEqu.h>
+#include <Script.h>
+#include <SetUpA4.h>
#include "util.h"
/* ALRT resources */
@@ -1157,6 +1159,85 @@ ModalDialogFilter(DialogPtr dlg, EventRecord *event, s
}
return false;
+}
+
+static short _password_dialog_ditl_id = -1;
+static char *_password_dialog_storage = NULL;
+static size_t _password_dialog_storage_len = 0;
+
+void
+PasswordDialogFieldFilterSetup(short ditl_id, char *storage, size_t len)
+{
+ _password_dialog_ditl_id = ditl_id;
+ _password_dialog_storage = storage;
+ _password_dialog_storage_len = len;
+
+ memset(_password_dialog_storage, 0, len);
+}
+
+pascal bool
+PasswordDialogFieldFilter(DialogPtr dlg, EventRecord *event, short *hit)
+{
+ DialogPeek dlgp;
+ WindowPtr event_win;
+ short event_in, sel_start, sel_end;
+ char key;
+
+ dlgp = (DialogPeek)dlg;
+ if (dlgp->editField == _password_dialog_ditl_id - 1) {
+ sel_start = (*(dlgp->textH))->selStart;
+ sel_end = (*(dlgp->textH))->selEnd;
+
+ switch (event->what) {
+ case keyDown:
+ case autoKey:
+ key = event->message & charCodeMask;
+ if (event->modifiers & cmdKey) {
+ /* TODO: implement DlgPaste for cmd+v? */
+ event->what = nullEvent;
+ return false;
+ }
+
+ if (key == 8) {
+ /* backspace */
+ if (sel_start == sel_end && sel_start > 0)
+ memmove(_password_dialog_storage + sel_start - 1,
+ _password_dialog_storage + sel_start,
+ _password_dialog_storage_len - sel_start - 1);
+ else if (sel_start != sel_end)
+ memmove(_password_dialog_storage + sel_start,
+ _password_dialog_storage + sel_end,
+ _password_dialog_storage_len - sel_end - 1);
+ } else if (sel_start >= _password_dialog_storage_len) {
+ event->what = nullEvent;
+ return false;
+ } else if (key >= ' ' && key <= '~') {
+ if (sel_start != sel_end)
+ /* delete selection before making space for new char */
+ memmove(_password_dialog_storage + sel_start,
+ _password_dialog_storage + sel_end,
+ _password_dialog_storage_len - sel_end - 1);
+ memmove(_password_dialog_storage + sel_start + 1,
+ _password_dialog_storage + sel_start,
+ _password_dialog_storage_len - sel_start - 1);
+ _password_dialog_storage[sel_start] = key;
+ event->message = '•';
+ }
+ _password_dialog_storage[(*(dlgp->textH))->teLength + 1] = '\0';
+ sel_start = 0;
+ break;
+ }
+ }
+
+ return ModalDialogFilter(dlg, event, hit);
+}
+
+void
+PasswordDialogFieldFinish(void)
+{
+ _password_dialog_ditl_id = -1;
+ _password_dialog_storage = NULL;
+ _password_dialog_storage_len = 0;
}
/* (*(some_te))->caretHook = NullCaretHook; */
--- util.h Thu Feb 3 16:26:22 2022
+++ util.h Mon Feb 7 16:05:45 2022
@@ -122,6 +122,11 @@ void SetTrackControlTE(TEHandle te);
pascal void TrackMouseDownInControl(ControlHandle control, short part);
pascal bool ModalDialogFilter(DialogPtr dlg, EventRecord *event,
short *hit);
+void PasswordDialogFieldFilterSetup(short ditl_id, char *storage,
+ size_t len);
+pascal bool PasswordDialogFieldFilter(DialogPtr dlg, EventRecord *event,
+ short *hit);
+void PasswordDialogFieldFinish(void);
pascal void NullCaretHook(void);
#endif
--- wallops.π.r Sun Feb 6 20:34:55 2022
+++ wallops.π.r Mon Feb 7 17:04:12 2022
@@ -32,34 +32,29 @@ data 'DITL' (128) {
};
data 'DITL' (129, "CONNECT_DITL") {
- $"000C 0000 0000 00BE 006E 00D2 00B8 0407" /* .......æ.n.“.∏.. */
- $"436F 6E6E 6563 7400 0000 0000 000A 006E" /* Connect........n */
- $"001A 011B 1000 0000 0000 0028 006E 0038" /* ...........(.n.8 */
- $"00A2 1004 3636 3637 0000 0000 0046 006E" /* .¢..6667.....F.n */
- $"0056 00CC 1000 0000 0000 0064 006E 0074" /* .V.Ã.......d.n.t */
- $"00CC 1000 0000 0000 0082 006E 0093 011C" /* .Ã.......Ç.n.ì.. */
- $"1000 0000 0000 00A0 006E 00B1 00CC 1000" /* .......†.n.±.Ã.. */
- $"0000 0000 000A 000A 001A 0055 8807 5365" /* ...........Uà.Se */
- $"7276 6572 3A0C 0000 0000 0028 000A 0038" /* rver:......(...8 */
- $"005E 880C 5365 7276 6572 2050 6F72 743A" /* .^à.Server Port: */
- $"0000 0000 0046 000A 0056 0055 8805 4E69" /* .....F...V.Uà.Ni */
- $"636B 3A06 0000 0000 0064 000A 0074 0055" /* ck:......d...t.U */
- $"8806 4964 656E 743A 0000 0000 0082 000A" /* à.Ident:.....Ç.. */
- $"0092 0055 880A 5265 616C 204E 616D 653A" /* .í.Uà.Real Name: */
- $"0000 0000 00A0 000A 00B0 0055 8808 4368" /* .....†...∞.Uà.Ch */
- $"616E 6E65 6C3A" /* annel: */
+ $"000E 0000 0000 00DC 0096 00F0 00E0 0407" /* .........ñ...... */
+ $"436F 6E6E 6563 7400 0000 0000 000A 0096" /* Connect........ñ */
+ $"001A 0144 1000 0000 0000 0028 0096 0038" /* ...D.......(.ñ.8 */
+ $"00CA 1004 3636 3637 0000 0000 0046 0096" /* . ..6667.....F.ñ */
+ $"0056 00F4 1000 0000 0000 0064 0096 0074" /* .V.........d.ñ.t */
+ $"00F4 1000 0000 0000 0082 0096 0092 00F4" /* .........Ç.ñ.í.. */
+ $"1000 0000 0000 00A0 0096 00B0 0144 1000" /* .......†.ñ.∞.D.. */
+ $"0000 0000 00BE 0096 00CE 00F4 1000 0000" /* .....æ.ñ.Œ...... */
+ $"0000 000A 000A 001A 0055 8807 5365 7276" /* .........Uà.Serv */
+ $"6572 3A0C 0000 0000 0028 000A 0038 005E" /* er:......(...8.^ */
+ $"880C 5365 7276 6572 2050 6F72 743A 0000" /* à.Server Port:.. */
+ $"0000 0046 000A 0056 0089 8810 5365 7276" /* ...F...V.âà.Serv */
+ $"6572 2050 6173 7377 6F72 643A 0000 0000" /* er Password:.... */
+ $"0064 000A 0074 0055 8805 4E69 636B 3A3A" /* .d...t.Uà.Nick:: */
+ $"0000 0000 0082 000A 0092 0055 8806 4964" /* .....Ç...í.Uà.Id */
+ $"656E 743A 0000 0000 00A0 000A 00B0 0055" /* ent:.....†...∞.U */
+ $"880A 5265 616C 204E 616D 653A 0000 0000" /* à.Real Name:.... */
+ $"00BE 000A 00CF 0072 880D 4A6F 696E 2043" /* .æ...œ.rà¬Join C */
+ $"6861 6E6E 656C 3A00" /* hannel:. */
};
-data 'LDEF' (128, "mailbox list", purgeable) {
- $"2F3A 0004 4E75 0000 0000" /* /:..Nu.... */
-};
-
-data 'LDEF' (129, "message list") {
- $"2F3A 0004 4E75 0000 0000" /* /:..Nu.... */
-};
-
data 'DLOG' (129, "CONNECT_DLOG") {
- $"0048 0066 0122 018E 0004 0000 0100 0000" /* .H.f.".é........ */
+ $"003C 0056 0137 01A7 0004 0000 0100 0000" /* .<.V.7.ß........ */
$"0000 0081 1143 6F6E 6E65 6374 2074 6F20" /* ...Å.Connect to */
$"5365 7276 6572" /* Server */
};