diff dmessage.c @ 3:5a977ccbc7a9 default tip

Empty changelog
author darius
date Sat, 06 Dec 1997 05:41:29 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmessage.c	Sat Dec 06 05:41:29 1997 +0000
@@ -0,0 +1,778 @@
+/* $Id: dmessage.c,v 1.1.1.1 1997/12/06 05:41:29 darius Exp $ */
+
+/*
+ * dmessage.c
+ *
+ * for the client of a socket based protocol.
+ * code for message window scrollback added by Bill Dyess 12/7/93
+ */
+#include "copyright.h"
+
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef __STDC__
+#include <stdlib.h>
+#endif
+#include "Wlib.h"
+#include "defs.h"
+#include "struct.h"
+#include "data.h"
+#include "proto.h"
+#ifdef SOUND
+#include "Slib.h"
+#endif
+
+#define MESSAGESIZE	20
+#define YOFF		0
+
+struct messageData {
+    char   *message;
+    unsigned char flags, from, to;
+};
+
+struct messageNode {
+    struct messageData *line;
+    struct messageNode *next, *prev;
+};
+
+/* Prototypes */
+int instr P((char *string1, char *string2));
+void CheckFeatures P((char *m));
+void print_message 
+P((char *message, unsigned int flags, unsigned int from,
+   unsigned int to, struct messageData * data,
+   W_Window winmask, int backwards));
+    void evalFlags P((int type, char *flagList));
+
+    void    initMessageWindows()
+{
+    int     i;
+    char   *s;
+
+    messWin[WALL].window = W_MakeScrollingWindow("review_all", WINSIDE + BORDER,
+						 YOFF + WINSIDE + 3 * BORDER + 2 * MESSAGESIZE, 80, 10, 0, "xterm", BORDER);
+    messWin[WTEAM].window = W_MakeScrollingWindow("review_team", WINSIDE + BORDER,
+      YOFF + WINSIDE + 4 * BORDER + 2 * MESSAGESIZE + 10 * W_Textheight + 8,
+						  80, 5, 0, "xterm", BORDER);
+    messWin[WINDIV].window = W_MakeScrollingWindow("review_your", WINSIDE + BORDER,
+     YOFF + WINSIDE + 5 * BORDER + 2 * MESSAGESIZE + 15 * W_Textheight + 16,
+						 80, 4, 0, "xterm", BORDER);
+    messWin[WKILL].window = W_MakeScrollingWindow("review_kill", WINSIDE + BORDER,
+     YOFF + WINSIDE + 6 * BORDER + 2 * MESSAGESIZE + 19 * W_Textheight + 24,
+						  80, 6, 0, "xterm", BORDER);
+    messWin[WPHASER].window = W_MakeScrollingWindow("review_phaser", WINSIDE +
+    BORDER, YOFF + WINSIDE + 7 * BORDER + 2 * MESSAGESIZE + 24 * W_Textheight
+					   + 32, 80, 3, 0, "xterm", BORDER);
+    messWin[WREVIEW].window = W_MakeScrollingWindow("review", WINSIDE + BORDER,
+			      YOFF + WINSIDE + 3 * BORDER + 2 * MESSAGESIZE,
+						80, 20, 0, "xterm", BORDER);
+
+    /*
+       initialize the 'allow' flags.  Any window can display any message.
+       [BDyess]
+    */
+    s = stringDefault("review_all.allow", "MA");
+    evalFlags(WALL, s);
+    s = stringDefault("review_team.allow", "T");
+    evalFlags(WTEAM, s);
+    s = stringDefault("review_your.allow", "I");
+    evalFlags(WINDIV, s);
+    s = stringDefault("review_kill.allow", "K");
+    evalFlags(WKILL, s);
+    s = stringDefault("review_phaser.allow", "P");
+    evalFlags(WPHASER, s);
+    s = stringDefault("review.allow", "MATIKP");
+    evalFlags(WREVIEW, s);
+
+    for (i = 0; i < WNUM; i++) {
+	messWin[i].head = messWin[i].curHead = NULL;
+    }
+}
+
+void
+evalFlags(type, flagList)
+    int     type;
+    char   *flagList;
+{
+    char *orig=flagList;
+
+    messWin[type].flags = 0;
+    while (*flagList) {
+	switch (toupper(*flagList)) {
+	case 'A':
+	    messWin[type].flags |= WA_ALL;
+	    break;
+	case 'T':
+	    messWin[type].flags |= WA_TEAM;
+	    break;
+	case 'I':
+	    messWin[type].flags |= WA_INDIV;
+	    break;
+	case 'K':
+	    messWin[type].flags |= WA_KILL;
+	    break;
+	case 'P':
+	    messWin[type].flags |= WA_PHASER;
+	    break;
+	case 'M':
+	    messWin[type].flags |= WA_MACRO;
+	    break;
+	default:
+	    printf("Invalid allow flag '%c' in allow list, ignoring\n",
+		   *flagList);
+	    break;
+	}
+	flagList++;
+    }
+    free(orig);
+}
+
+void
+messageWinEvent(evt)
+    W_Event *evt;
+/* handles the mouse and keyboard events that happen in one of the message
+   windows.  For key events, if the event is within the team or all window then
+   it will automatically start the message for you, with destination to the
+   player's team or ALL, respectively.  If it's a button event, it will scroll
+   the message window back, forward, or to start (left, right, and middle
+   button respectively).  It beeps if there is no messages to scroll (ie at
+   the top or bottom already). [BDyess] 12/07/93 */
+{
+    struct messageNode **headpntr, *runner, *newcpntr;
+    struct messageData *j;
+    int     windowHeight;
+    register int i;
+    W_Window window = evt->Window;
+    int     key = evt->key;
+    int scroll=0;
+
+    if (!W_IsMapped(window))
+	return;
+
+    if (evt->type == W_EV_KEY) {
+	if (key == ('e' + 128)) {	/* erase window [BDyess] */
+	    W_ClearWindow(window);
+	} else if(key == ('p'+128)) {
+	    scroll = -1;
+	} else if(key == ('n'+128)) {
+	    scroll = 1;
+	} else if (window == messWin[WALL].window) {
+	    smessage_ahead('A', key);
+	} else if (window == messWin[WTEAM].window) {
+	    smessage_ahead('T', key);
+	} else {
+	    smessage(key);
+	}
+	if(!scroll)
+	    return;
+    }
+    headpntr = NULL;
+    for (i = 0; i < WNUM; i++) {
+	if (window == messWin[i].window) {
+	    headpntr = &messWin[i].curHead;
+	    break;
+	}
+    }
+
+    runner = *headpntr;
+    if (runner == NULL) {
+	if(scrollBeep)
+	    W_Beep();
+	return;
+    }
+    windowHeight = W_WindowHeight(window);
+
+    if(scroll==-1) {
+	for (i = 0; (i < windowHeight) && runner; i++, runner = runner->next)
+            ;
+	if (runner == NULL) {
+	    if (scrollBeep)
+		W_Beep();
+	    return;
+	}
+	j=runner->line;
+	print_message(j->message, j->flags, j->from, j->to, NULL, window, 1);
+	*headpntr = (*headpntr)->next;
+	return;
+    } else if(scroll==1) {
+	if(runner->prev == NULL) {
+	    if (scrollBeep)
+		W_Beep();
+	    return;
+	}
+	j=runner->prev->line;
+	print_message(j->message, j->flags, j->from, j->to, NULL, window, 0);
+	*headpntr = (*headpntr)->prev;
+	return;
+    }
+    switch (key) {
+    case W_LBUTTON:
+	for (i = 0; (i < windowHeight-1) && runner->next; i++, runner = runner->next)
+	    ;
+	newcpntr=runner;
+	
+	if (runner->next == NULL) {
+	    if (scrollBeep)
+		W_Beep();
+	    break;
+	}
+	runner=runner->next;
+	for (i = 0; (i < windowHeight-1) && runner; i++, runner = runner->next) {
+	    j=runner->line;
+	    print_message(j->message, j->flags, j->from, j->to, NULL, window, 1);
+	}
+	if(i<windowHeight-1) {
+	    for(;i<windowHeight-1;i++)
+		W_WriteText(window,0,-1,0,"",0,0);
+	}
+	*headpntr=newcpntr;
+	break;
+    case W_RBUTTON:
+	if (runner->prev == NULL) {
+	    if (scrollBeep)
+		W_Beep();
+	    break;
+	}
+	for (i = 0; (i < windowHeight-1) && runner->prev; i++, runner = runner->prev) {
+	    j=runner->prev->line;
+	    print_message(j->message, j->flags, j->from, j->to, NULL, window, 0);
+	}
+	*headpntr = runner;
+	break;
+    case W_MBUTTON:
+	if (runner->prev == NULL) {
+	    if (scrollBeep)
+		W_Beep();
+	    break;
+	}
+	W_ClearWindow(window);
+	while (runner->prev)
+	    runner = runner->prev;
+	*headpntr = runner;
+	for (i = 0; i < windowHeight && runner->next; i++, runner = runner->next);
+	while (runner) {
+	    j = runner->line;
+	    print_message(j->message, j->flags, j->from, j->to, NULL, window, 0);
+	    runner = runner->prev;
+	}
+	break;
+    }
+}
+
+void
+rsvp_borg_call(message, from)
+    char   *message;
+    int     from;
+{
+#if 0
+    int     len, pos;
+    len = strlen(message);
+    pos = len - 5;
+    if (strncmp(message + pos, "     ", 5) == 0)
+#else
+    char   *chk;
+
+    if (strlen(message) < 15)
+	return;
+    for (chk = message + 10; *chk && *chk == ' '; chk++)
+	 /* empty body */ ;
+    if (*chk)
+	return;
+#endif
+    {
+	char    buf[120];
+
+	sprintf(buf, "Paradise Client %s (%s)", CLIENTVERS,
+#ifdef __osf__
+		"DEC OSF/1"
+#else
+#ifdef NeXT
+		"NeXT"
+#else
+#ifdef ultrix
+		"DEC Ultrix"
+#else
+#if defined(sparc) && defined(SVR4)
+		"Solaris"
+#else
+#ifdef sparc
+		"SUN4/Sparc"
+#else
+#ifdef sun
+		"SUN3"
+#else
+#ifdef sequent
+		"sequent"
+#else
+#ifdef hpux
+		"hpux"
+#else
+#ifdef AIX
+		"AIX"
+#else
+#ifdef vax
+		"vax"
+#else
+#ifdef sgi
+		"sgi/IRIX"
+#else
+#ifdef apollo
+		"apollo"
+#else
+#ifdef RS6K
+		"RS6K"
+#else
+#ifdef linux
+		"Linux"
+#else
+#ifdef __NetBSD__
+		"NetBSD"
+#else
+#ifdef __FreeBSD__
+		"FreeBSD"
+#else
+#ifdef AMIGA
+		"Amiga"
+#else
+		"generic"
+#endif				/* Amiga */
+#endif				/* linux */
+#endif				/* RS6K */
+#endif				/* apollo */
+#endif				/* sgi */
+#endif				/* vax */
+#endif				/* AIX */
+#endif				/* hpux */
+#endif				/* sequent */
+#endif				/* sun */
+#endif				/* sparc */
+#endif				/* solaris */
+#endif				/* ultrix */
+#endif				/* NeXT */
+#endif				/* __osf__ */
+#endif				/* FreeBSD */
+#endif				/* NetBSD */
+	    );
+	if (from == 255) {
+	    sendMessage(buf, MGOD, 0);
+	} else
+	    sendMessage(buf, MINDIV, from);
+    }
+}
+
+void
+logit(message)
+    char   *message;
+/* logs the given message if the 'logmess' variable is set to one.  It send the
+   message to stdout by default, or to a file if one is defined. [BDyess] */
+{
+    if (!logmess)
+	return;
+    if (logfilehandle && logFile) {
+	fprintf(logfilehandle, "%s\n", message);
+	fflush(logfilehandle);
+    } else {
+	printf("%s\n", message);
+    }
+}
+
+void
+writeMessage(data, message, color, len, winmask, type, backwards)
+    struct messageData *data;
+    char   *message;
+    W_Color color;
+    int     len;
+    W_Window winmask;
+    int     type;
+    int     backwards;
+{
+    struct messageNode *newhead;
+    struct messageWin *j;
+
+    if (data != NULL) {
+#ifdef SPEECH /* was AMIGA... ya never know ;-) */
+	if (((S_SpeakYour && type & WA_INDIV) ||
+	     (S_SpeakTeam && type & WA_TEAM) ||
+	     (S_SpeakAll && type & WA_ALL) ||
+	     (S_SpeakKill && type & WA_KILL)) &&
+	    ((strncmp(message,"GOD->",5) != 0) || S_SpeakGod) &&
+	    ((data->from != me->p_no) || S_SpeakSelf)) {
+	    S_SpeakString(message, len);
+	}
+#endif				/* SPEECH */
+#ifdef SOUND
+	if ((type & WA_INDIV) && data->from != me->p_no) {
+	    S_PlaySound(S_WHISTLE);
+	}
+#endif
+	for (j = &messWin[0]; j < &messWin[WNUM]; j++) {
+	    if (!(j->flags & type))
+		continue;
+	    newhead = (struct messageNode *) malloc(sizeof(struct messageNode));
+	    newhead->next = j->head;
+	    if (newhead->next)
+		newhead->next->prev = newhead;
+	    newhead->prev = NULL;
+	    newhead->line = data;
+	    if (j->head == j->curHead) {
+		/* we aren't currently scrolled back [BDyess] */
+		W_WriteText(j->window, 0, 0, color, message, len, 0);
+		j->curHead = newhead;
+	    }
+	    j->head = newhead;
+	}
+    } else {			/* we're drawing a new page */
+	for (j = &messWin[0]; j < &messWin[WNUM]; j++) {
+	    if (!(j->flags & type))
+		continue;
+	    if (j->window != winmask)
+		continue;
+	    W_WriteText(j->window, 0, (backwards ? -1 : 0), color, message, len, 0);
+	}
+    }
+}
+
+void
+print_message(message, flags, from, to, data, winmask, backwards)
+    char   *message;
+    unsigned int flags, from, to;
+    struct messageData *data;
+    W_Window winmask;
+    int backwards;
+/* this function determines the color that the given message should be and
+   then passes it to writeMessage, where the data structure for the scroll
+   back code is created and also where the winmask test is done.  The winmask
+   determines what window the message is written to, useful when calling this
+   routine from the scrollback routines.  If winmask == NULL it doesn't
+   limit printing at all, eg team messages will go to the team window and to
+   the total review window.  [BDyess] 12/07/93 */
+{
+    register int len;
+    W_Color color;
+    W_Window targwin;
+
+#define    take  MTEAM + MTAKE + MVALID
+#define    destroy  MTEAM + MDEST + MVALID
+#define    kill  MALL + MKILL + MVALID
+#define    killp  MALL + MKILLP + MVALID
+#define    killa  MALL + MKILLA + MVALID
+#define    bomb  MTEAM + MBOMB + MVALID
+#define    team  MTEAM + MVALID
+#define    conq  MALL + MCONQ + MVALID
+
+    len = strlen(message);
+    if (from == 254) {		/* client passing info around */
+	switch (showPhaser) {
+	case 0:
+	    break;
+	case 1:
+	    writeMessage(data, message, textColor, len, winmask, WA_KILL | WA_REVIEW, backwards);
+	    break;
+	case 2:
+	    writeMessage(data, message, textColor, len, winmask, WA_REVIEW | WA_PHASER, backwards);
+	    break;
+	case 3:
+	    writeMessage(data, message, textColor, len, winmask, WA_REVIEW, backwards);
+	    break;
+	}
+	return;
+    }
+    if (from == 255) {
+	if (flags == MCONFIG + MINDIV + MVALID) {
+/*       printf("Going to checkfeatures\n");*/
+	    CheckFeatures(message);
+	    return;
+	}
+	/* From God */
+	color = textColor;
+    } else {
+	/* kludge to fix the occasional incorrect color message */
+	if (*message == ' ' && from != me->p_no) {
+	    /* XXX fix to handle funky teams */
+	    switch (*(message + 1)) {
+	    case 'F':
+		color = W_Yellow;
+		break;
+	    case 'R':
+		color = W_Red;
+		break;
+	    case 'K':
+		color = W_Green;
+		break;
+	    case 'O':
+		color = W_Cyan;
+		break;
+	    case 'I':
+		color = W_Grey;
+		break;
+	    default:
+		color = playerColor(&(players[from]));
+	    }
+	} else
+	    color = playerColor(&(players[from]));
+    }
+
+    /* added/modified to fit with the scrollback feature 1/94 -JR */
+    if (!paradise && niftyNewMessages) {
+	if (flags == conq) {
+	    /* output conquer stuff to stdout in addition to message window */
+	    fprintf(stdout, "%s\n", message);
+	    if (instr(message, "kill")) {
+		fprintf(stdout, "NOTE: The server here does not properly set message flags\n");
+		fprintf(stdout, "You should probably pester the server god to update....\n");
+	    }
+	}
+	if ((flags == team) || (flags == take) || (flags == destroy)) {
+	    writeMessage(data, message, color, len, winmask, WA_TEAM | WA_REVIEW, backwards);
+	    targwin = messWin[WTEAM].window;
+	} else if ((flags == kill) || (flags == killp) || (flags == killa) || (flags == bomb)) {
+	    writeMessage(data, message, color, len, winmask,
+			 WA_KILL | (reportKills ? WA_REVIEW : 0), backwards);
+	    targwin = messWin[WKILL].window;
+	} else if (flags & MINDIV) {
+	    writeMessage(data, message, color, len, winmask, (WA_INDIV | WA_REVIEW), backwards);
+	    targwin = messWin[WINDIV].window;
+	} else if (flags == (MMACRO | MALL)) {
+	    writeMessage(data, message, color, len, winmask, (WA_MACRO | WA_REVIEW), backwards);
+	    targwin = messWin[WALL].window;
+	} else {
+	    /*
+	       if we don't know where the message belongs by this time, stick
+	       it in the all board...
+	    */
+	    writeMessage(data, message, color, len, winmask, (WA_ALL | WA_REVIEW), backwards);
+	    targwin = messWin[WALL].window;
+	}
+    } else {
+
+	/*
+	   Kludge stuff for report kills...
+	*/
+	if ((strncmp(message, "GOD->ALL", 8) == 0 &&
+	     (instr(message, "was kill") ||
+	      instr(message, "killed by"))) ||
+	    instr(message, "burned to a crisp by") ||
+	    instr(message, "shot down by") ||
+	    (*message != ' ' && instr(message, "We are being attacked"))) {
+	    writeMessage(data, message, color, len, winmask,
+			 WA_KILL | (reportKills ? WA_REVIEW : 0), backwards);
+	    return;
+	}
+	/*
+	   note: messages are kept track of even if the associated window is
+	   not mapped.  This allows the window to be later mapped and have
+	   all the past messages. [BDyess]
+	*/
+	if (flags & MTEAM) {
+	    writeMessage(data, message, color, len, winmask, WA_TEAM | WA_REVIEW, backwards);
+	    targwin = messWin[WTEAM].window;
+	} else if (flags & MINDIV) {
+	    writeMessage(data, message, color, len, winmask, WA_INDIV | WA_REVIEW, backwards);
+	    targwin = messWin[WINDIV].window;
+	} else if (flags == (MMACRO | MALL)) {
+	    writeMessage(data, message, color, len, winmask, WA_MACRO | WA_REVIEW, backwards);
+	    targwin = messWin[WALL].window;
+	} else {
+	    writeMessage(data, message, color, len, winmask, WA_ALL | WA_REVIEW, backwards);
+	    targwin = messWin[WALL].window;
+	}
+    }
+    /*
+       send warnings to warning or message window, if player doesn't have
+       messag es mapped
+    */
+    if ((use_msgw && (targwin == messWin[WINDIV].window || targwin == messWin[WTEAM].window)) ||
+	(!W_IsMapped(targwin) && !W_IsMapped(messWin[WREVIEW].window))) {
+	if (!messpend && messagew) {	/* don't collide with messages being
+					   written! */
+	    W_ClearWindow(messagew);
+	    W_WriteText(messagew, 5, 5, color, message, len, W_RegularFont);
+	} else
+	    warning(message);
+    }
+}
+
+void
+dmessage(message, flags, from, to)
+    char   *message;
+    unsigned int flags, from, to;
+/* prints the given message by going though several subroutines.  Here, it first
+   creates the data structure that holds the message info and logs the message,
+   then sends it on it's subroutine path to print it to the correct window(s).
+   This is a good place to handle any special-functions that occur due to
+   incoming messages.  The data structure for the scroll back is like this:
+   each window has a head pointer that points to the top of its message
+   list.  Each list only contains the messages that go to it's window.  The
+   lists have pointers to the message itself, so that only one copy of the
+   message exists even if it is displayed on several windows.  Each list also
+   has a current head pointer that points to the record that is at the bottom
+   of that current window.  If the current head pointer and the head pointer
+   are different, then the window must be scrolled back.  In such a case, new
+   messages are still received but not printed.  [BDyess] 12/07/93 */
+{
+    struct messageData *data;
+    struct distress dist;
+    int len;
+
+#ifdef RC_DISTRESS
+    /* aha! A new type distress/macro call came in. parse it appropriately */
+    if (F_gen_distress && (flags == (MTEAM | MDISTR | MVALID))) {
+	HandleGenDistr(message, from, to, &dist);
+	len = makedistress(&dist, message, distmacro[dist.distype].macro);
+#ifdef BEEPLITE
+	if (UseLite)
+	    rcdlite(&dist);
+#endif
+	if (len <= 0)
+	    return;
+	flags ^= MDISTR;
+    }
+#endif
+    /*
+       add create message data struct.  Used for message scrollback
+       capability.  [BDyess]
+    */
+    data = (struct messageData *) malloc(sizeof(struct messageData));
+    data->message = (char *) strdup(message);
+    data->flags = flags;
+    data->from = from;
+    data->to = to;
+    /*
+       keep track of how many queued messages there are for use with the
+       infoIcon [BDyess]
+    */
+    if (infoIcon) {
+	if (to == me->p_no && flags & MINDIV) {	/* personal message */
+	    me_messages++;
+	} else if (flags & MTEAM) {	/* team message */
+	    team_messages++;
+	} else {		/* message for all */
+	    all_messages++;
+	}
+	if (iconified)
+	    drawIcon();
+    }
+    logit(message);
+
+    /*
+       fix for upgrade bug.  Forced UDP would resend numbers, (thinking them
+       speed changes) screwing up upgrading on those twinkish sturgeon
+       servers. [BDyess]
+    */
+    if (strncmp(message, "UPG->", 5) == 0)
+	upgrading = 1;
+    if (upgrading && !(me->p_flags & PFORBIT))
+	upgrading = 0;
+
+    if ((from != me->p_no) || pigSelf)
+	rsvp_borg_call(message, from);
+
+    /* beep when a personal message is sent while iconified [BDyess] */
+    if (to == me->p_no && (flags & MINDIV) && iconified) {
+	W_Beep();
+    }
+    if (from == 255 &&
+	strcmp(message, "Tractor beam aborted warp engagement") == 0) {
+	me->p_flags &= ~PFWARPPREP;
+    }
+    print_message(message, flags, from, to, data, NULL, 0);
+}
+
+
+int
+instr(string1, string2)
+    char   *string1, *string2;
+{
+    char   *s;
+    int     length;
+
+    length = strlen(string2);
+    for (s = string1; *s != 0; s++) {
+	if (*s == *string2 && strncmp(s, string2, length) == 0)
+	    return (1);
+    }
+    return (0);
+}
+
+void
+CheckFeatures(m)
+    char   *m;
+/* I don't know if this works correctly or not.  It is ripped from BRM and has
+   been modified a bit to fit.  Right now it doesn't do anything.  [BDyess] */
+{
+    char    buf[BUFSIZ];
+    char   *pek = &m[10];
+
+    if ((int) strlen(m) < 11)
+	return;
+
+    while ((*pek == ' ') && (*pek != '\0'))
+	pek++;
+
+    strcpy(buf, "Paradise Client: ");
+
+    if (!strcmp(pek, "NO_VIEW_BOX")) {
+	allowViewBox = 0;
+	strcat(buf, pek);
+    }
+#ifdef CONTINUOUS_MOUSE
+    if (!strcmp(pek, "NO_CONTINUOUS_MOUSE")) {
+	allowContinuousMouse = 0;
+	strcat(buf, pek);
+    }
+#endif				/* CONTINUOUS_MOUSE */
+    if (!strcmp(pek, "NO_SHOW_ALL_TRACTORS")) {
+	allowShowAllTractorPressor = 0;
+	strcat(buf, pek);
+    }
+    if (!strcmp(pek, "HIDE_PLAYERLIST_ON_ENTRY")) {
+	allowPlayerlist = 0;
+	strcat(buf, pek);
+    }
+    if (!strcmp(pek, "NO_NEWMACRO")) {
+/*      UseNewMacro = 0;*/
+	strcat(buf, pek);
+    }
+    if (!strcmp(pek, "NO_SMARTMACRO")) {
+/*      UseSmartMacro = 0;*/
+	strcat(buf, pek);
+    }
+    if (!strcmp(pek, "WHY_DEAD")) {
+	why_dead = 1;
+	strcat(buf, pek);
+    }
+    if (!strcmp(pek, "RC_DISTRESS")) {
+/*      gen_distress = 1;*/
+/*      distmacro = dist_prefered;*/
+	strcat(buf, pek);
+    }
+    /* what the hell is this? - jmn */
+    if (!strncmp(pek, "INFO", 4)) {
+	strcat(buf, pek);
+    }
+    if (strlen(buf) == strlen("Paradise Client: ")) {
+	strcat(buf, "UNKNOWN FEATURE: ");
+	strcat(buf, pek);
+    }
+    buf[79] = '\0';
+
+    printf("%s\n", buf);
+
+    W_WriteText(messWin[WREVIEW].window, 0, 0, W_White, buf, strlen(buf), 0);
+    W_WriteText(messWin[WALL].window, 0, 0, W_White, buf, strlen(buf), 0);
+}
+
+void
+sendVersion()
+{
+    static int version_sent = 0;
+    char    buf[80];
+
+    if (!version_sent) {
+	version_sent = 1;
+	sprintf(buf, "@%s", CLIENTVERS);
+	pmessage(buf, me->p_no, MINDIV | MCONFIG);
+    }
+}