[mw-devel] [Git][arthur/mw][master] Add mw_logon, mw_logoff, talker_join and talker_leave mwjs events

Andrew Price welshbyte at sucs.org
Sat Nov 3 15:08:09 GMT 2018


Andrew Price pushed to branch master at Justin Mitchell / mw


Commits:
ccde2b85 by Andrew Price at 2018-11-03T15:06:09+00:00
Add mw_logon, mw_logoff, talker_join and talker_leave mwjs events

Required a lot of IPC_CHECKONOFF-related changes and tidy-ups.
New js events handled like so:

    function handler(ev)
    {
            switch(ev.type) {
            case "mw_logon":
                    d = ev.data;
                    mw.print("d.user: " + d.user);
                    mw.print("d.quiet: " + d.quiet);

                    mw.print("d.autochat: " + d.autochat);
                    break;
            case "mw_logoff":
                    d = ev.data;
                    mw.print("d.user: " + d.user);
                    mw.print("d.method: " + d.method);
                    mw.print("d.quiet: " + d.quiet);

                    mw.print("d.reason: " + d.reason);
                    mw.print("d.agent: " + d.agent);
                    break;
            case "talker_join":
                    d = ev.data;
                    mw.print("d.user: " + d.user);
                    mw.print("d.method: " + d.method);
                    mw.print("d.quiet: " + d.quiet);

                    mw.print("d.channel: " + d.channel);
                    mw.print("d.agent: " + d.agent);
                    break;
            case "talker_leave":
                    d = ev.data;
                    mw.print("d.user: " + d.user);
                    mw.print("d.method: " + d.method);
                    mw.print("d.quiet: " + d.quiet);

                    mw.print("d.channel: " + d.channel);
                    mw.print("d.agent: " + d.agent);
                    mw.print("d.message: " + d.message);
                    break;
            }
    }
    mw.onevent.push(handler);

See src/server/PROTOCOL and src/onoff.h for hints on what those fields
are.

- - - - -


12 changed files:

- src/client/event.h
- src/client/incoming.c
- src/client/js-duk.c
- src/client/main.c
- src/client/main.h
- src/client/newmain.c
- + src/client/onoff.c
- + src/client/onoff.h
- src/client/script_inst.c
- src/client/talker.c
- + src/onoff.h
- src/server/PROTOCOL


Changes:

=====================================
src/client/event.h
=====================================
--- a/src/client/event.h
+++ b/src/client/event.h
@@ -6,12 +6,14 @@
 typedef enum {
 	MWEV_TYPE_NONE = 0,
 	MWEV_TYPE_MSG,
+	MWEV_TYPE_ONOFF,
 } mwev_type_t;
 
 struct mwevent {
 	mwev_type_t ev_type;
 	union {
-		ipc_message_t *msg; /* MWEV_TYPE_MSG */
+		ipc_message_t *msg;   /* MWEV_TYPE_MSG */
+		ipc_message_t *onoff; /* MWEV_TYPE_ONOFF */
 	} ev_data;
 };
 


=====================================
src/client/incoming.c
=====================================
--- a/src/client/incoming.c
+++ b/src/client/incoming.c
@@ -31,6 +31,7 @@
 #include "gaglist.h"
 #include "js.h"
 #include "event.h"
+#include "onoff.h"
 #include <jansson.h>
 #include <str_util.h>
 
@@ -50,14 +51,13 @@ static void force_text(ipc_message_t *msg, const char *text, const char *from);
 static void force_vtext(ipc_message_t *msg, const char *from, const char *format, ...) __attribute__((format (printf, 3, 4)));
 static void force_ipc(char *text, char *from);
 static void force_rpc(char *text, char *from);
-static void force_checkonoff(char *text, char *from);
 static void force_wiz(ipc_message_t *msg, char *text, char *from);
-static void force_chatmode(char *text, unsigned long theirprivs, const char *from);
+static void force_chatmode(char *text, struct user *usr);
 static void force_status(char *text, char *from);
 static void force_channel(char *text, char *from, unsigned long theirprivs);
 static void force_kick(char *text, char *from, unsigned long theirprivs);
 static void force_gag(char *text, unsigned long theirprivs, const char *from);
-static void zod(char *from, char *msg);
+static void zod(const char *from, const char *msg);
 static void mrod(char *from, char *msg);
 static void force_newmail(void);
 static void force_protlevel(char *text, unsigned long theirprivs, const char *from);
@@ -176,11 +176,37 @@ void DisplayStack(void)
 			}
 			case EST_CHECKONOFF:
 			{
-				char	*aargs[6];
-				char	*backup;
-				char	*onoff_name, *sep, *head, *head2;
-				char	*uname, *reason = NULL;
-				int	ccode, method, isquiet;
+				struct {
+					char ccode[13];
+					char type[13];
+					char quiet[3];
+					char name[NAMESIZE + 1];
+					char version[3];
+					char reason[MAXTEXTLENGTH];
+				} a;
+				char *aargs[6] = {
+					a.ccode,
+					a.type,
+					a.quiet,
+					a.name,
+					a.version,
+					a.reason
+				};
+				int action_to_ccode[] = {
+					[ONOFF_LOGON] = 3,
+					[ONOFF_LOGOFF] = 2,
+					[ONOFF_JOIN] = 1,
+					[ONOFF_LEAVE] = 0,
+				};
+				char *onoff_name;
+				const char *uname, *reason;
+				int ccode, isquiet, action, type;
+				struct mwevent ev = {
+						.ev_type = MWEV_TYPE_ONOFF,
+						.ev_data.onoff = new->msg,
+				};
+				script_output = 1;
+				js_handle_event(&ev);
 
 				/* go through list and find checkonoff function */
 				onoff_name = NULL;
@@ -189,209 +215,75 @@ void DisplayStack(void)
 				/* if no function found, skip everything else */
 				if (onoff_name == NULL) break;
 
-				/* backup the input text */
-				backup = strdup(new->text);
-
-				/* get the first comma in the checkonoff code */
-				sep = strchr(new->text, ',');
-
-				/* if this comma does not exist, use the original version of checkonoff */
-				if (sep == NULL)
-				{
-					/* simply convert to a number */
-					ccode = atoi(new->text);
-
-					/* due to backwards compatibility issues, we can only use 0 or 1 */
-					if (ccode < 0) { free(backup); break; }
-					if (ccode > 1) { free(backup); break; }
-
-					/* create memory for argument strings */
-					aargs[0] = malloc(sizeof(char) * 13);
-					aargs[1] = malloc(sizeof(char) * 13);
-					aargs[2] = malloc(sizeof(char) * 3);
-					aargs[3] = malloc(sizeof(char) * NAMESIZE + 1);
-					aargs[4] = malloc(sizeof(char) * 3);
-					aargs[5] = malloc(sizeof(char) * MAXTEXTLENGTH);
-
-					/* set up the argument strings */
-					snprintf(aargs[0], 12, "%d", ccode);
-					aargs[1][0] = 0;
-					aargs[2][0] = 0;
-					aargs[3][0] = 0;
-					snprintf(aargs[4], 2, "1");
-					aargs[5][0] = 0;
-
-					/* run the event */
-					ExecEvent2(onoff_name, "CheckOnOff", new->from, 0, 6, aargs);
-
-					/* free memory and break out */
-					free(backup);
-					free(aargs[0]);
-					free(aargs[1]);
-					free(aargs[2]);
-					free(aargs[3]);
-					free(aargs[4]);
-					free(aargs[5]);
-					break;
-				}
-
-				/* set head to the character after the comma, and terminate the code before the comma */
-				head = sep + 1;
-				*sep = 0;
-
-				/* get the checkonoff code number */
-				ccode = atoi(new->text);
-
-				/* get the next comma in the checkonoff code */
-				sep = strchr(head, ',');
-				/* if no comma found, then this must be an interim checkonoff */
-				if (sep == NULL)
-				{
-					/* due to backwards compatibility issues, we can only use 0 or 1 */
-					if (ccode < 0) { free(backup); break; }
-					if (ccode > 1) { free(backup); break; }
-
-					/* simply convert the next argument to a number */
-					isquiet = atoi(head);
-
-					/* create memory for argument strings */
-					aargs[0] = malloc(sizeof(char) * 13);
-					aargs[1] = malloc(sizeof(char) * 13);
-					aargs[2] = malloc(sizeof(char) * 3);
-					aargs[3] = malloc(sizeof(char) * NAMESIZE + 1);
-					aargs[4] = malloc(sizeof(char) * 3);
-					aargs[5] = malloc(sizeof(char) * MAXTEXTLENGTH);
-
-					/* set up the argument strings */
-					snprintf(aargs[0], 12, "%d", ccode);
-					aargs[1][0] = 0;
-					snprintf(aargs[2], 2, "%d", isquiet);
-					aargs[3][0] = 0;
-					snprintf(aargs[4], 2, "2");
-					aargs[5][0] = 0;
-
-					/* run the event */
-					ExecEvent2(onoff_name, "CheckOnOff", new->from, 0, 6, aargs);
-
-					/* free memory and break out */
-					free(backup);
-					free(aargs[0]);
-					free(aargs[1]);
-					free(aargs[2]);
-					free(aargs[3]);
-					free(aargs[4]);
-					free(aargs[5]);
-					break;
-				}
-
-				/* set second text head to the character after the comma, and terminate the method before the comma */
-				head2 = sep + 1;
-				*sep = 0;
-
-				/* get the checkonoff method number */
-				method = atoi(head);
-
-				/* get the next comma in the checkonoff code */
-				sep = strchr(head2, ',');
-				/* if no comma found, then this must be broken! */
-				if (sep == NULL)
-				{
-					printf("Invalid checkonoff broadcast received! (%s)\n", backup);
-					free(backup);
+				json_t *j = ipcmsg_json_decode(new->msg);
+				uname = json_getstring(j, "user");
+				action = json_getint(j, "action");
+				type = json_getint(j, "type");
+				isquiet = json_is_true(json_object_get(j, "quiet"));
+				if (action == ONOFF_LOGOFF)
+					reason = json_getstring(j, "reason");
+				else
+					reason = json_getstring(j, "message");
+
+				if (action >= ONOFF_SIZE)
 					break;
-				}
-
-				/* set uname to the character after the comma, and terminate the method before the comma */
-				uname = sep + 1;
-				*sep = 0;
-
-				/* get the checkonoff quiet flagr */
-				isquiet = atoi(head2);
 
-				/* get the optional next comma in the checkonoff code */
-				sep = strchr(uname, ',');
-				/* if comma is found, then the reason is there */
-				if (sep != NULL)
-				{
-					reason = sep + 1;
-					*sep = 0;
-				}
+				ccode = action_to_ccode[action];
 
 				/* limit the method information */
-				switch (ccode)
-				{
-				/* leave the talker */
-				case 0:
-					if (!cp_test(user, CP_CANZOD) && (method == 1))
+				switch (action) {
+				case ONOFF_LEAVE:
+					if (!cp_test(user, CP_CANZOD) && (type == LEAVE_ZOD))
 					{
-						method = 0;
+						type = 0;
 						uname = new->from;
 					}
-					if (!u_god(user) && (method == 2))
+					if (!u_god(user) && (type == LEAVE_FORCED))
 					{
-						method = 0;
+						type = 0;
 						uname = new->from;
 					}
 					break;
-				/* enter the talker */
-				case 1:
-					if (!cp_test(user, CP_SUMMON) && (method == 1))
+				case ONOFF_JOIN:
+					if (!cp_test(user, CP_SUMMON) && (type == JOIN_SUMMONED))
 					{
-						method = 0;
+						type = 0;
 						uname = new->from;
 					}
-					if (!u_god(user) && (method == 2))
+					if (!u_god(user) && (type == JOIN_FORCED))
 					{
-						method = 0;
+						type = 0;
 						uname = new->from;
 					}
 					break;
-				/* leave the board */
-				case 2:
-					if (!cp_test(user, CP_CANMROD) && (method == 3))
+				case ONOFF_LOGOFF:
+					if (!cp_test(user, CP_CANMROD) && (type == LOGOFF_MROD))
 					{
-						method = 0;
+						type = 0;
 						uname = new->from;
 					}
-					if (!u_god(user) && ((method == 4) || (method == 5) || (method == 6)))
+					if (!u_god(user) && (
+					    (type == LOGOFF_BANNED) ||
+					    (type == LOGOFF_ERROR) ||
+					    (type == LOGOFF_DELETED)))
 					{
-						method = 0;
+						type = 0;
 						uname = new->from;
 					}
 					break;
-				/* enter the board */
-				case 3:
+				case ONOFF_LOGON:
 					break;
 				}
-
-				/* create memory for argument strings */
-				aargs[0] = malloc(sizeof(char) * 13);
-				aargs[1] = malloc(sizeof(char) * 13);
-				aargs[2] = malloc(sizeof(char) * 3);
-				aargs[3] = malloc(sizeof(char) * NAMESIZE + 1);
-				aargs[4] = malloc(sizeof(char) * 3);
-				aargs[5] = malloc(sizeof(char) * MAXTEXTLENGTH);
-
 				/* set up the argument strings */
-				snprintf(aargs[0], 12, "%d", ccode);
-				snprintf(aargs[1], 12, "%d", method);
-				snprintf(aargs[2], 2, "%d", isquiet);
-				snprintf(aargs[3], NAMESIZE, "%s", uname);
-				snprintf(aargs[4], 2, "3");
-				if (reason) snprintf(aargs[5], MAXTEXTLENGTH - 1, "%s", reason);
-				else aargs[5][0] = 0;
-
-				/* display the broadcast message */
+				memset(&a, 0, sizeof(a));
+				snprintf(a.ccode, 12, "%d", ccode);
+				snprintf(a.type, 12, "%d", type);
+				snprintf(a.quiet, 2, "%d", isquiet ? 1 : 0);
+				snprintf(a.name, NAMESIZE, "%s", uname);
+				a.version[0] = '3';
+				if (reason != NULL)
+					snprintf(a.reason, MAXTEXTLENGTH - 1, "%s", reason);
 				ExecEvent2(onoff_name, "CheckOnOff", new->from, 0, 6, aargs);
-
-				/* free up the memory used */
-				free(aargs[0]);
-				free(aargs[1]);
-				free(aargs[2]);
-				free(aargs[3]);
-				free(aargs[4]);
-				free(aargs[5]);
-				free(backup);
 				break;
 			}
 			default:
@@ -477,7 +369,7 @@ static void handle_ipc_error(ipc_message_t *msg)
 		printf("Undefined server error '%s'\n", type);
 	}
 	json_decref(j);
-	close_down(0, NULL, NULL);
+	close_down(LOGOFF_NORMAL, NULL, NULL);
 }
 
 static void display_error(ipc_message_t *msg)
@@ -659,12 +551,20 @@ static void display_content(ipc_message_t *msg)
 		json_array_foreach(j, i, jgag) {
 			gaglist_append(json_string_value(jgag));
 		}
+	} else
+	if (msg->head.type == IPC_CHECKONOFF && cp_test(user, CP_SCRIPT)) {
+		struct mstack *ms;
+
+		ms = calloc(1, sizeof(*ms));
+		ms->flags = MST_SCREV;
+		ms->preamble = EST_CHECKONOFF;
+		ms->from = strdup(whom);
+		InsertMesg(ms, msg);
 	} else {
 		printf("Unknown message type %4.4s", (char *)&msg->head.type);
 	}
 
 	json_decref(j);
-
 }
 
 static void accept_pipe_cmd(ipc_message_t *msg, struct user *mesg_user)
@@ -703,7 +603,7 @@ static void accept_pipe_cmd(ipc_message_t *msg, struct user *mesg_user)
 			user->record.chatprivs = cp_setbycode(user->record.chatprivs, newbuff);
 			break;
 		case IPC_CHATMODE:
-			force_chatmode(newbuff, mesg_user->record.chatprivs, mesg_user->record.name);
+			force_chatmode(newbuff, mesg_user);
 			break;
 		case IPC_GAG:
 			force_gag(newbuff, mesg_user->record.chatprivs, mesg_user->record.name);
@@ -738,7 +638,7 @@ static void accept_pipe_cmd(ipc_message_t *msg, struct user *mesg_user)
 			force_rpc(newbuff, mesg_user->record.name);
 			break;
 		case IPC_CHECKONOFF:
-			force_checkonoff(newbuff, mesg_user->record.name);
+			display_content(msg);
 			break;
 		case IPC_WIZ:
 			force_wiz(msg, newbuff, mesg_user->record.name);
@@ -862,14 +762,6 @@ static void force_wiz(ipc_message_t *msg, char *newbuff, char *from)
 	InsertMesg(mesg, msg);
 }
 
-static void force_checkonoff(char *text, char *from)
-{
-	if (cp_test(user, CP_SCRIPT))
-	{
-		StackEvent(text, from, EST_CHECKONOFF);
-	}
-}
-
 static void force_ipc(char *text, char *from)
 {
 	if (cp_test(user, CP_SCRIPT))
@@ -893,39 +785,35 @@ static void force_status(char *newbuff, char *from)
 	if (u_ban(user))
 	{
 		printf(_("\n\n--> You appear to have been banned. Goodbye... <--\r\n"));
-		close_down(4, from, NULL);
+		close_down(LOGOFF_BANNED, from, NULL);
 	}
 	/* we have received a +D status change */
 	if (u_del(user))
 	{
 		printf(_("\n\n--> You appear to have been DELETED. Goodbye... <--\r\n"));
-		close_down(6, from, NULL);
+		close_down(LOGOFF_DELETED, from, NULL);
 	}
 }
 
-static void force_chatmode(char *newbuff, unsigned long theirprivs, const char *from)
+static void force_chatmode(char *newbuff, struct user *usr)
 {
-	unsigned long	mm;
-	int		ourapl = (user->record.chatprivs & CP_PROTMASK) >> CP_PROTSHIFT;
-	int		theirapl = (theirprivs & CP_PROTMASK) >> CP_PROTSHIFT;
-	int		oldchat;
+	unsigned long mm;
+	int ourapl = (user->record.chatprivs & CP_PROTMASK) >> CP_PROTSHIFT;
+	int theirapl = (usr->record.chatprivs & CP_PROTMASK) >> CP_PROTSHIFT;
+	int oldchat;
 
-	if (!(theirprivs & CP_PROTECT)) theirapl = 0;
+	if (!(usr->record.chatprivs & CP_PROTECT)) theirapl = 0;
 	oldchat = cm_test(user, CM_ONCHAT);
 
 	mm=cm_setbycode(user->record.chatmode, newbuff);
-	user->record.chatmode=chatmode_describe(user->record.chatmode, mm, ourapl, theirapl, from);
+	user->record.chatmode = chatmode_describe(user->record.chatmode, mm, ourapl, theirapl, NULL);
 
 	if (!cm_test(user, CM_ONCHAT) && oldchat)
-	{
-		/* announce leaving talker */
-		broadcast_onoffcode(0, 2, from, NULL);
-	}
+		announce_leave(user->record.name, user->record.room, LEAVE_FORCED,
+		               usr->record.name, NULL, quietmode);
 	else if (cm_test(user, CM_ONCHAT) && !oldchat)
-	{
-		/* announce joining the talker */
-		broadcast_onoffcode(1, 2, from, NULL);
-	}
+		announce_join(user->record.name, user->record.room, JOIN_FORCED,
+		              usr->record.name, quietmode);
 
 	disable_rl(1);
 }
@@ -1014,10 +902,7 @@ static void force_channel(char *newbuff, char *from, unsigned long theirprivs)
 
 			/* run common talker entrance code with logon type set to 'summon' */
 			enter_talker(2);
-
-			/* give an entrance broadcast */
-			broadcast_onoffcode(1, 1, from, NULL);
-
+			announce_join(user->record.name, user->record.room, JOIN_SUMMONED, from, quietmode);
 			enter_room(newroom);
 		}
 	}else
@@ -1076,18 +961,15 @@ static void force_kick(char *newbuff, char *from, unsigned long theirprivs)
 	}
 }
 
-static void zod(char *from, char *msg)
+static void zod(const char *from, const char *msg)
 {
 	char text[MAXTEXTLENGTH];
 
 	/* remove from talker */
 	user->record.chatmode = cm_clear(user, CM_ONCHAT);
 
-	/* force update of user */
 	update_user(user);
-
-	/* announce leaving talker via zod */
-	broadcast_onoffcode(0, 1, from, msg);
+	announce_leave(user->record.name, user->record.room, LEAVE_ZOD, from, msg, quietmode);
 
 	/* put standard message to screen */
 	snprintf(text, MAXTEXTLENGTH-1, _("\nBoing, Zebedee arrived.  \"%s\033--\", said Zebedee\n"), (msg!=NULL)?msg:_("Time for bed"));
@@ -1129,5 +1011,5 @@ static void mrod(char *from, char *msg)
 
 	mrod_user = malloc(sizeof(char) * (strlen(from) + 1));
 	strcpy(mrod_user, from);
-	close_down(3, from, msg);
+	close_down(LOGOFF_MROD, from, msg);
 }


=====================================
src/client/js-duk.c
=====================================
--- a/src/client/js-duk.c
+++ b/src/client/js-duk.c
@@ -23,6 +23,7 @@
 #include "iconv.h"
 #include "sqlite.h"
 #include "init.h"
+#include "onoff.h"
 
 extern struct user * const user;
 struct alarm *timeout_event = NULL;
@@ -204,6 +205,125 @@ static int js_push_ipcmsg_event(ipc_message_t *msg)
 	return 0;
 }
 
+static int js_push_logon_event(json_t *j, duk_idx_t i, int type)
+{
+	duk_push_boolean(ctx, type == LOGON_AUTOCHAT);
+	duk_put_prop_string(ctx, i, "autochat");
+	return 0;
+}
+
+static int js_push_logoff_event(json_t *j, duk_idx_t i, int type)
+{
+	const char *reason;
+	const char *agent;
+	const char *subtypes[] = {
+		[LOGOFF_NORMAL] = "normal",
+		[LOGOFF_TIMEOUT] = "timeout",
+		[LOGOFF_EOFS] = "eof",
+		[LOGOFF_MROD] = "mrod",
+		[LOGOFF_BANNED] = "banned",
+		[LOGOFF_ERROR] = "error",
+		[LOGOFF_DELETED] = "deleted"
+	};
+	if (type > LOGOFF_DELETED || type < 0) {
+		fprintf(stderr, "mwjs error: bad logoff event type: %d\n", type);
+		duk_pop(ctx);
+		return 1;
+	}
+	duk_push_string(ctx, subtypes[type]);
+	duk_put_prop_string(ctx, i, "method");
+	reason = json_getstring(j, "reason");
+	if (reason != NULL) {
+		duk_push_string(ctx, reason);
+		duk_put_prop_string(ctx, i, "reason");
+	}
+	agent = json_getstring(j, "agent");
+	if (agent != NULL) {
+		duk_push_string(ctx, agent);
+		duk_put_prop_string(ctx, i, "agent");
+	}
+	return 0;
+}
+
+static int js_push_join_event(json_t *j, duk_idx_t i, int type)
+{
+	const char *agent = json_getstring(j, "agent");
+	const char *subtypes[] = {
+		[JOIN_NORMAL] = "normal",
+		[JOIN_SUMMONED] = "summoned",
+		[JOIN_FORCED] = "forced",
+	};
+	if (type > JOIN_FORCED || type < 0) {
+		fprintf(stderr, "mwjs error: bad join event type: %d\n", type);
+		duk_pop(ctx);
+		return 1;
+	}
+	duk_push_string(ctx, subtypes[type]);
+	duk_put_prop_string(ctx, i, "method");
+	if (agent != NULL) {
+		duk_push_string(ctx, agent);
+		duk_put_prop_string(ctx, i, "agent");
+	}
+	duk_push_number(ctx, json_getint(j, "channel"));
+	duk_put_prop_string(ctx, i, "channel");
+	return 0;
+}
+
+static int js_push_leave_event(json_t *j, duk_idx_t i, int type)
+{
+	const char *agent = json_getstring(j, "agent");
+	const char *msg = json_getstring(j, "message");
+	const char *subtypes[] = {
+		[LEAVE_NORMAL] = "normal",
+		[LEAVE_ZOD] = "zod",
+		[LEAVE_FORCED] = "forced",
+		[LEAVE_EXIT] = "logoff",
+	};
+	if (type > LEAVE_EXIT || type < 0) {
+		fprintf(stderr, "mwjs error: bad leave event type: %d\n", type);
+		duk_pop(ctx);
+		return 1;
+	}
+	duk_push_string(ctx, subtypes[type]);
+	duk_put_prop_string(ctx, i, "method");
+	if (agent != NULL) {
+		duk_push_string(ctx, agent);
+		duk_put_prop_string(ctx, i, "agent");
+	}
+	if (msg != NULL) {
+		duk_push_string(ctx, msg);
+		duk_put_prop_string(ctx, i, "message");
+	}
+	duk_push_number(ctx, json_getint(j, "channel"));
+	duk_put_prop_string(ctx, i, "channel");
+	return 0;
+}
+
+static int (*js_push_onoff_func[ONOFF_SIZE])(json_t*, duk_idx_t, int) = {
+	js_push_logon_event,
+	js_push_logoff_event,
+	js_push_join_event,
+	js_push_leave_event
+};
+
+/* Pushes the event object and attaches the common bits to it before calling
+ * the onoff action type-specific function to fill in the rest */
+static int js_push_onoff_event(json_t *j, int action)
+{
+	duk_idx_t idx = duk_push_bare_object(ctx);
+	int type = json_getint(j, "type");
+	int ret;
+
+	duk_push_boolean(ctx, json_is_true(json_object_get(j, "quiet")));
+	duk_put_prop_string(ctx, idx, "quiet");
+	duk_push_string(ctx, json_getstring(j, "user"));
+	duk_put_prop_string(ctx, idx, "user");
+
+	ret = js_push_onoff_func[action](j, idx, type);
+	json_decref(j);
+	return ret;
+}
+
 static duk_ret_t js_print(duk_context *cx)
 {
 	int argc = duk_get_top(cx);
@@ -756,6 +876,24 @@ static int js_push_event(struct mwevent *ev)
 		if (ret == 0)
 			duk_put_prop_string(ctx, idx, "data");
 		break;
+	case MWEV_TYPE_ONOFF:
+		duk_require_stack(ctx, 2);
+		/* ONOFF covers 4 different types of events so expose them as
+		   separate event types to reduce js boilerplate */
+		json_t *j = ipcmsg_json_decode(ev->ev_data.onoff);
+		if (j == NULL) {
+			fprintf(stderr, "mwjs error: failed to unmarshall message\n");
+			return -1;
+		}
+		int action = json_getint(j, "action");
+		if (action >= ONOFF_SIZE || action < 0)
+			break;
+		duk_push_string(ctx, onoff_action_name[action]);
+		duk_put_prop_string(ctx, idx, "type");
+		ret = js_push_onoff_event(j, action);
+		if (ret == 0)
+			duk_put_prop_string(ctx, idx, "data");
+		break;
 	case MWEV_TYPE_NONE:
 		/* Fall through */
 	default:


=====================================
src/client/main.c
=====================================
--- a/src/client/main.c
+++ b/src/client/main.c
@@ -54,6 +54,7 @@
 #include "userio.h"
 #include "who.h"
 #include "alias.h"
+#include "onoff.h"
 
 static char version[]="Milliways III - Release "VERSION"\n";
 
@@ -198,7 +199,7 @@ static void accept_line(char *line)
 			broadcast(1, "\03304%s'%s connection has just dropped.", user->record.name,
 			          user->record.name[strlen(user->record.name)] == 's' ? "" : "s");
 			mwlog("EOF(LOGOUT)");
-			close_down(2, NULL, NULL);
+			close_down(LOGOFF_EOFS, NULL, NULL);
 		}
 	} else
 	{
@@ -727,8 +728,7 @@ int main(int argc, char **argv)
 
 	/* run all board init functions */
 	RunInitFuncs(0);
-	/* broadcast board logon signal to other users */
-	broadcast_onoffcode(3, autochat, NULL, NULL);
+	announce_logon(user->record.name, autochat ? LOGON_AUTOCHAT : LOGON_NORMAL, quietmode);
 
 	/* autochat - log onto talker immediately */
 	if (autochat && u_reg(user)) t_chaton();
@@ -757,7 +757,7 @@ int main(int argc, char **argv)
 			fflush(stdout);
 			perror("stdin");
 			mwlog("ERROR on stdin");
-			close_down(5, NULL, NULL);
+			close_down(LOGOFF_ERROR, NULL, NULL);
 		}
 		if (!busy && MesgIsStacked())
 		{
@@ -837,7 +837,7 @@ void accept_command(char *cmd)
 	}
 }
 
-void close_down(int exitmode, char *sourceuser, char *reason)
+void close_down(int logofftype, char *sourceuser, char *reason)
 {
 	extern char *event_user;
 	extern char *event_body_text;
@@ -862,19 +862,10 @@ void close_down(int exitmode, char *sourceuser, char *reason)
 				else ExecEvent(shutdown_name, "", "ShutDown", NULL, 0);
 			}
 		}
-		/* give 'straight to shell' logoff code */
-		broadcast_onoffcode(0, 3, sourceuser, NULL);
+		announce_leave(user->record.name, user->record.room, LEAVE_EXIT, sourceuser, NULL, quietmode);
 	}
 
-	/* send different broadcast depending on exitmode */
-	/* 0 - normal */
-	/* 1 - timeout */
-	/* 2 - too many eof's */
-	/* 3 - mrod */
-	/* 4 - banned */
-	/* 5 - error */
-	broadcast_onoffcode(2, exitmode, sourceuser, reason);
-
+	announce_logoff(user->record.name, logofftype, sourceuser, reason, quietmode);
 
 	/* update user information */
 	time_t now = time(0);
@@ -904,11 +895,8 @@ void close_down(int exitmode, char *sourceuser, char *reason)
 	stop_js();
 	alarm_cleanup();
 
-	/* dont display logoff text if quiet, or if dropped */
-	if (!quietmode && exitmode!=1 && exitmode!=2)
-	{
+	if (!quietmode && logofftype != LOGOFF_TIMEOUT && logofftype != LOGOFF_EOFS)
 		broadcast(1, "\03302%s has just left the board.", user->record.name);
-	}
 
 	mwlog("LOGOUT");
 	sleep(1); //dodgy hack for race condition in checkonoff, cunningly we currently get woken by the very message we're waiting for.
@@ -1261,7 +1249,7 @@ static void time_out(void *idle_count_p)
 
 		broadcast(1, _("\03304%s has been timed out."), user->record.name);
 		mwlog("TIMEOUT(LOGOUT)");
-		close_down(1, NULL, NULL);
+		close_down(LOGOFF_TIMEOUT, NULL, NULL);
 	}
 	else if (*icnt==0)
 	{
@@ -1274,7 +1262,7 @@ static void time_out(void *idle_count_p)
 	else
 	{
 		mwlog("TIMEOUT(BLOCKED)");
-		close_down(1, NULL, NULL);
+		close_down(LOGOFF_TIMEOUT, NULL, NULL);
 	}
 
 }
@@ -1846,26 +1834,3 @@ void devel_msg(const char *func, const char *fmt, ...)
 	if (cp_test(user, CP_DEVEL))
 		printf("\n*** WARNING (%s): %s\n", func, text);
 }
-
-
-void broadcast_onoffcode(int ocode, int method, const char *sourceuser, const char *reason)
-{
-	char logofftext[MAXTEXTLENGTH];
-	extern int talker_logontype;
-	const char *usr;
-
-	if (sourceuser == NULL)
-		usr = user->record.name;
-	else
-		usr = sourceuser;
-
-	if (reason == NULL)
-		snprintf(logofftext, MAXTEXTLENGTH-1, "%d,%d,%d,%s", ocode, method,
-		         talker_logontype & LOGONMASK_QUIET, usr);
-	else
-		snprintf(logofftext, MAXTEXTLENGTH-1, "%d,%d,%d,%s,%s", ocode, method,
-		         talker_logontype & LOGONMASK_QUIET, usr, reason);
-
-	logofftext[MAXTEXTLENGTH-1] = '\0';
-	ipc_send_to_all(IPC_CHECKONOFF, logofftext);
-}


=====================================
src/client/main.h
=====================================
--- a/src/client/main.h
+++ b/src/client/main.h
@@ -5,7 +5,6 @@ void close_down(int exitmode, char *sourceuser, char *reason);
 void display_message(const char *text, int beeps, int newline);
 void format_message(const char *format, ...) __attribute__((format(printf,1,0)));
 void printfile(const char *filename);
-void broadcast_onoffcode(int code, int method, const char *sourceuser, const char *reason);
 void reset_timeout(int secs);
 int idle(int fd, int millis);
 void set_rights(void);


=====================================
src/client/newmain.c
=====================================
--- a/src/client/newmain.c
+++ b/src/client/newmain.c
@@ -38,6 +38,7 @@
 #include "userio.h"
 #include "mesg.h"
 #include "incoming.h"
+#include "onoff.h"
 #include <util.h>
 
 extern int currentfolder,last_mesg;
@@ -1025,7 +1026,7 @@ void c_date(CommandList *cm, int argc, const char **argv, char *args)
 
 void c_quit(CommandList *cm, int argc, const char **argv, char *args)
 {
-	close_down(0, NULL, NULL);
+	close_down(LOGOFF_NORMAL, NULL, NULL);
 }
 
 void c_save(CommandList *cm, int argc, const char **argv, char *args)


=====================================
src/client/onoff.c
=====================================
--- /dev/null
+++ b/src/client/onoff.c
@@ -0,0 +1,99 @@
+#include <ipc.h>
+#include "onoff.h"
+
+extern struct user * const user;
+
+const char *onoff_action_name[ONOFF_SIZE] = {
+	[ONOFF_LOGON] = "mw_logon",
+	[ONOFF_LOGOFF] = "mw_logoff",
+	[ONOFF_JOIN] = "talker_join",
+	[ONOFF_LEAVE] = "talker_leave"
+};
+
+int announce_logon(const char *usr, int type, int quiet)
+{
+	ipc_message_t *msg;
+	json_t *j;
+
+	j = json_init(NULL);
+	json_addstring(j, "user", usr);
+	json_addint(j, "action", ONOFF_LOGON);
+	json_addint(j, "type", type);
+	json_object_set(j, "quiet", json_boolean(quiet));
+
+	msg = ipcmsg_create(IPC_CHECKONOFF, user->posn);
+	ipcmsg_destination(msg, SYSTEM_USER);
+	ipcmsg_json_encode(msg, j);
+	json_decref(j);
+	ipcmsg_transmit(msg);
+	return 0;
+}
+
+int announce_logoff(const char *usr, int type, const char *agent, const char *reason, int quiet)
+{
+	ipc_message_t *msg;
+	json_t *j;
+
+	j = json_init(NULL);
+	json_addstring(j, "user", usr);
+	json_addint(j, "action", ONOFF_LOGOFF);
+	json_addint(j, "type", type);
+	json_object_set(j, "quiet", json_boolean(quiet));
+	if (agent != NULL)
+		json_addstring(j, "agent", agent);
+	if (reason != NULL)
+		json_addstring(j, "reason", reason);
+
+	msg = ipcmsg_create(IPC_CHECKONOFF, user->posn);
+	ipcmsg_destination(msg, SYSTEM_USER);
+	ipcmsg_json_encode(msg, j);
+	json_decref(j);
+	ipcmsg_transmit(msg);
+	return 0;
+}
+
+int announce_join(const char *usr, int channel, int type, const char *agent, int quiet)
+{
+	ipc_message_t *msg;
+	json_t *j;
+
+	j = json_init(NULL);
+	json_addstring(j, "user", usr);
+	json_addint(j, "action", ONOFF_JOIN);
+	json_addint(j, "channel", channel);
+	json_addint(j, "type", type);
+	json_object_set(j, "quiet", json_boolean(quiet));
+	if (agent != NULL)
+		json_addstring(j, "agent", agent);
+
+	msg = ipcmsg_create(IPC_CHECKONOFF, user->posn);
+	ipcmsg_destination(msg, SYSTEM_USER);
+	ipcmsg_json_encode(msg, j);
+	json_decref(j);
+	ipcmsg_transmit(msg);
+	return 0;
+}
+
+int announce_leave(const char *usr, int channel, int type, const char *agent, const char *lmsg, int quiet)
+{
+	ipc_message_t *msg;
+	json_t *j;
+
+	j = json_init(NULL);
+	json_addstring(j, "user", usr);
+	json_addint(j, "action", ONOFF_LEAVE);
+	json_addint(j, "channel", channel);
+	json_addint(j, "type", type);
+	json_object_set(j, "quiet", json_boolean(quiet));
+	if (agent != NULL)
+		json_addstring(j, "agent", agent);
+	if (lmsg != NULL)
+		json_addstring(j, "message", lmsg);
+
+	msg = ipcmsg_create(IPC_CHECKONOFF, user->posn);
+	ipcmsg_destination(msg, SYSTEM_USER);
+	ipcmsg_json_encode(msg, j);
+	json_decref(j);
+	ipcmsg_transmit(msg);
+	return 0;
+}


=====================================
src/client/onoff.h
=====================================
--- /dev/null
+++ b/src/client/onoff.h
@@ -0,0 +1,13 @@
+#ifndef ONOFF_H
+#define ONOFF_H
+
+#include <onoff.h>
+
+extern const char *onoff_action_name[ONOFF_SIZE];
+
+int announce_logon(const char *usr, int type, int quiet);
+int announce_logoff(const char *usr, int type, const char *agent, const char *reason, int quiet);
+int announce_join(const char *usr, int channel, int type, const char *agent, int quiet);
+int announce_leave(const char *usr, int channel, int type, const char *agent, const char *msg, int quiet);
+
+#endif /* ONOFF_H */


=====================================
src/client/script_inst.c
=====================================
--- a/src/client/script_inst.c
+++ b/src/client/script_inst.c
@@ -27,6 +27,7 @@
 #include "mesg.h"
 #include "util.h"
 #include "who.h"
+#include "onoff.h"
 
 extern struct user * const user;
 /* current script runaway variable */
@@ -462,8 +463,7 @@ void scr_talkpriv( struct code *pc, int fargc, char **fargv )
 
 void scr_quit( struct code *pc, int fargc, char **fargv )
 {
-	/* close down milliways normally */
-	close_down(0, NULL, NULL);
+	close_down(LOGOFF_NORMAL, NULL, NULL);
 }
 
 void scr_exec( struct code *pc, int fargc, char **fargv )


=====================================
src/client/talker.c
=====================================
--- a/src/client/talker.c
+++ b/src/client/talker.c
@@ -33,6 +33,7 @@
 #include "mesg.h"
 #include "incoming.h"
 #include "alias.h"
+#include "onoff.h"
 
 extern int busy; /* if true dont display messages  i.e. during new/write */
 extern unsigned long rights;
@@ -187,8 +188,7 @@ void t_quit(CommandList *cm, int argc, const char **argv, char *args)
 	snprintf(text, MAXTEXTLENGTH-1, "\03311%s has just left the talker", user->record.name);
 	if (!quietmode) talk_send_rawbcast(text);
 
-	/* announce log off talker */
-	broadcast_onoffcode(0, 0, NULL, NULL);
+	announce_leave(user->record.name, user->record.room, LEAVE_NORMAL, NULL, NULL, quietmode);
 	set_rights();
 }
 
@@ -1128,10 +1128,7 @@ void t_chaton(void)
 
 	/* run the common stuff for entering the talker */
 	enter_talker(1);
-
-	/* give an entrance broadcast */
-	broadcast_onoffcode(1, 0, NULL, NULL);
-
+	announce_join(urec->name, urec->room, JOIN_NORMAL, NULL, quietmode);
 	enter_room(urec->room);
 }
 


=====================================
src/onoff.h
=====================================
--- /dev/null
+++ b/src/onoff.h
@@ -0,0 +1,35 @@
+#ifndef MW_ONOFF_H
+#define MW_ONOFF_H
+
+enum onoff_action {
+	/* Relating to mw itself */
+	ONOFF_LOGON  = 0,
+	ONOFF_LOGOFF = 1,
+	/* Relating to the talker */
+	ONOFF_JOIN   = 2,
+	ONOFF_LEAVE  = 3,
+
+	ONOFF_SIZE /* Keep at end */
+};
+
+#define LOGON_NORMAL   0
+#define LOGON_AUTOCHAT 1
+
+#define LOGOFF_NORMAL  0
+#define LOGOFF_TIMEOUT 1
+#define LOGOFF_EOFS    2
+#define LOGOFF_MROD    3
+#define LOGOFF_BANNED  4
+#define LOGOFF_ERROR   5
+#define LOGOFF_DELETED 6
+
+#define JOIN_NORMAL   0
+#define JOIN_SUMMONED 1
+#define JOIN_FORCED   2
+
+#define LEAVE_NORMAL 0
+#define LEAVE_ZOD    1
+#define LEAVE_FORCED 2
+#define LEAVE_EXIT   3
+
+#endif /* MW_ONOFF_H */


=====================================
src/server/PROTOCOL
=====================================
--- a/src/server/PROTOCOL
+++ b/src/server/PROTOCOL
@@ -134,6 +134,25 @@ IPC_WHOLIST - list of all the users currently known to the system
 		    protection
 		    wizchat
 
+IPC_CHECKONOFF - Logon, logoff, talker join, talker leave events.
+	Body: (json)
+		user   - String; User who is doing the thing
+		action - Integer corresponding to the ONOFF_* values in onoff.h
+		type   - Integer subtype of action; one of the LOGON_*, LOGOFF_*,
+		         LEAVE_*, JOIN_* values.
+		quiet  - Boolean; true if the user is in quiet mode.
+		ONOFF_LOGON fields:
+			(none)
+		ONOFF_LOGOFF fields:
+			reason - (Optional) String; the reason for logging off
+			agent  - (Optional) String; who made this logoff happen
+		ONOFF_JOIN:
+			channel - Integer; currently unused (either on talker or not)
+			agent   - (Optional) String; who made this join happen
+		ONOFF_LEAVE:
+			channel - Integer; currently unused (either on talker or not)
+			agent   - (Optional) String; who made this leave happen
+			message - (Optional) String; what Zebedee says
 
 all other codes are old unformatted messages and are to be phased out,
 most commonly used is IPC_TEXT which is raw text to be displayed



View it on GitLab: https://projects.sucs.org/arthur/mw/commit/ccde2b8526802d6d0f19a740e110bfdff322ba84

-- 
View it on GitLab: https://projects.sucs.org/arthur/mw/commit/ccde2b8526802d6d0f19a740e110bfdff322ba84
You're receiving this email because of your account on projects.sucs.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.sucs.org/pipermail/mw-devel/attachments/20181103/4d0ef656/attachment-0001.html>


More information about the mw-devel mailing list