/
2.0.5/doc/
2.0.5/gnu/
2.0.5/sha/
/* notify.c */

#include "config.h"

/*
 *		       This file is part of TeenyMUD II.
 *		 Copyright(C) 1993, 1994, 1995 by Jason Downs.
 *                           All rights reserved.
 * 
 * TeenyMUD II is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * TeenyMUD II is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program (see the file 'COPYING'); if not, write to
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 * MA 02111-1307, USA.
 *
 */

/* AIX requires this to be the first thing in the file. */
#ifdef __GNUC__
#define alloca	__builtin_alloca
#else	/* not __GNUC__ */
#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#else	/* not HAVE_ALLOCA_H */
#ifdef _AIX
 #pragma alloca
#endif	/* not _AIX */
#endif	/* not HAVE_ALLOCA_H */
#endif 	/* not __GNUC__ */

#include <stdio.h>
#include <sys/types.h>
#ifdef HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif			/* HAVE_STRING_H */
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif			/* HAVE_STDLIB_H */

#include "conf.h"
#include "teeny.h"
#include "teenydb.h"
#include "externs.h"

/* routines for sending strings to players. */

static void nospoof_mesg _ANSI_ARGS_((char *, int, int, int));

void notify_bad(player)
    int player;
{
  notify_player(player, player, player,
  		"Something truly horrid just happened.  Good luck.", 0);
}

/* Emulate MUSH-style NOSPOOF output. */
static void nospoof_mesg(buf, player, cause, sender)
    char *buf;
    int player, cause, sender;
{
  char *sname, *soname;
  int sowner;

  if(get_str_elt(sender, NAME, &sname) != -1) {
    sprintf(buf, "[%s(#%d)", sname, sender);
  } else {
    sprintf(buf, "[(#%d", sender);
  }

  if(get_int_elt(sender, OWNER, &sowner) != -1) {
    if(sender != sowner) {
      if(get_str_elt(sowner, NAME, &soname) != -1)
	sprintf(&buf[strlen(buf)], "{%s}", soname);
    }
  }

  if(sender != cause)
    sprintf(&buf[strlen(buf)], "<-(#%d)", cause);

  strcat(buf, "]");
}

/* Ugh. */
void notify_player(player, cause, sender, str, nflags)
    int player, cause, sender;
    char *str;
    int nflags;
{
  char buf[MEDBUFFSIZ];
  char *lbuf;
  int owner, loc, oloc;
  register int i, j;
  register char *nstr, *cstr;
  char *name;

  if ((str == (char *)NULL) || (str[0] == '\0'))
    return;
  if (!can_hear(player))
    return;
  if ((nflags & NOT_QUIET) && (isQUIET(player) || isQUIET(sender)))
    return;

  /* we don't want to modify str. */
  lbuf = (char *)alloca(strlen(str)+1);
  if(lbuf == (char *)NULL)
    panic("notify_player: stack allocation failed.\n");
  strcpy(lbuf, str);
  nstr = lbuf;
  cstr = lbuf;

  while (nstr[0]) {
    for (; nstr[0] && (nstr[0] != '\n') && (nstr[0] != '\r'); nstr++);
    if ((nstr[0] == '\n') || (nstr[0] == '\r')) {
      nstr[0] = '\0';
      for (nstr++; nstr[0] &&
	   ((nstr[0] == '\n') || (nstr[0] == '\r')); nstr++);
    }
    if (isALIVE(player)) {
      if ((nflags & NOT_NOSPOOF) && isNOSPOOF(player)) {
	nospoof_mesg(buf, player, cause, sender);
	i = strlen(buf);
      } else
	i = 0;
      for (j = 0; (i < sizeof(buf)-2) && cstr[j]; i++, j++) {
	buf[i] = cstr[j];
      }
      buf[i] = '\0';

      if (nflags & NOT_RAW)
	tcp_notify_raw(player, buf);
      else
        tcp_notify(player, buf);
    }
    if (isPUPPET(player)) {
      switch (Typeof(player)) {
      case TYP_THING:
	if ((get_str_elt(player, NAME, &name) == -1)
	    || (get_int_elt(player, OWNER, &owner) == -1)
	    || (get_int_elt(player, LOC, &loc) == -1)
	    || (get_int_elt(owner, LOC, &oloc) == -1))
	  return;
	if (((nflags & NOT_NOPUPPET) && (loc == oloc)) || !isALIVE(owner))
	  break;
	if ((nflags & NOT_NOSPOOF) && isNOSPOOF(player)) {
	  nospoof_mesg(buf, player, cause, sender);
	  i = strlen(buf);
	} else
	  i = 0;

	for (j = 0; (i < sizeof(buf)-3) && name[j]; i++, j++) {
	  buf[i] = name[j];
	}

	buf[i++] = '>';
	buf[i++] = ' ';
	for (j = 0; (i < sizeof(buf)-2) && cstr[j]; i++, j++) {
	  buf[i] = cstr[j];
	}
	buf[i] = '\0';

	if (nflags & NOT_RAW)
	  tcp_notify_raw(owner, buf);
	else
	  tcp_notify(owner, buf);
	break;
      }
    }

    if (isLISTENER(player)) {
      if(player != sender) {
        attr_listen(player, cause, '^', cstr);
      } else {
	attr_listen(player, cause, '+', cstr);
      }
    }

    if (isAUDIBLE(player) && !isROOM(player) && !(nflags & NOT_NOAUDIBLE))
      notify_audible(player, cause, sender, cstr);

    cstr = nstr;
  }
}

void notify_audible(object, cause, sender, str)
    int object, cause, sender;
    char *str;
{
  char buf[MEDBUFFSIZ], *prefix, *filter;
  int aflags, source;
  register int i, j;

  if ((attr_get_parent(object, APREFIX, &prefix, &aflags, &source) == -1) ||
   (attr_get_parent(object, AFILTER, &filter, &aflags, &source) == -1))
    return;
  if ((filter != (char *) NULL) && filter_match(str, filter))
    return;
  if ((prefix == (char *) NULL) && isEXIT(object))
    prefix = "From a distance,";
  if (prefix && prefix[0]) {
    strcpy(buf, prefix);
    strcat(buf, " ");
  } else
    buf[0] = '\0';
  for (i = strlen(buf), j = 0; (i < MEDBUFFSIZ) && str[j]; i++, j++)
    buf[i] = str[j];
  buf[i] = '\0';

  if (isEXIT(object)) {
    int *dests, loc;

    if ((get_int_elt(object, LOC, &loc) == -1) ||
	(get_array_elt(object, DESTS, &dests) == -1) || (dests == (int *)NULL)
	|| (loc == dests[1]) || !exists_object(dests[1]) || isACTION(object))
      return;
    notify_contents(dests[1], cause, sender, buf, NOT_NOAUDIBLE);
  } else
    notify_contents(object, cause, sender, buf, NOT_NOAUDIBLE);
}

void notify_except2(player, cause, sender, string, except1, except2, nflags)
    int player, cause, sender;
    char *string;
    int except1, except2, nflags;
{
  int loc, list;

  if (!string || !string[0])
    return;

  if (get_int_elt(player, LOC, &loc) == -1) {
    logfile(LOG_ERROR, "notify_except2: bad location reference on object #%d\n",
	    player);
    return;
  }
  if (get_int_elt(loc, CONTENTS, &list) == -1) {
    logfile(LOG_ERROR, "notify_except2: bad contents reference on object #%d\n",
	    loc);
    return;
  }
  while (list != -1) {
    if ((list != except1) && (list != except2)) {
      notify_player(list, cause, sender, string, nflags);
    }
    if (get_int_elt(list, NEXT, &list) == -1) {
      logfile(LOG_ERROR, "notify_except2: bad next reference on object #%d\n",
	      list);
      return;
    }
  }
  if (!(nflags & NOT_NOAUDIBLE)) {
    if (get_int_elt(loc, EXITS, &list) == -1) {
      logfile(LOG_ERROR, "notify_except2: bad exits list on object #%d\n", loc);
      return;
    }
    while (list != -1) {
      if (isAUDIBLE(list) && (list != except1) && (list != except2))
	notify_audible(list, cause, sender, string);
      if (get_int_elt(list, NEXT, &list) == -1) {
	logfile(LOG_ERROR, "notify_except2: bad next reference on object #%d\n",
	        list);
	return;
      }
    }
  }
}

void notify_contents_except(loc, cause, sender, str, except, nflags)
    int loc, cause, sender;
    char *str;
    int except, nflags;
{
  int list;

  if (!has_contents(loc) || !str || !str[0])
    return;

  if (get_int_elt(loc, CONTENTS, &list) == -1) {
    logfile(LOG_ERROR,
	    "notify_contents_except: bad contents list on object #%d\n", list);
    return;
  }
  while (list != -1) {
    if ((except == -1) || (list != except)) {
      notify_player(list, cause, sender, str, nflags);
    }
    if (get_int_elt(list, NEXT, &list) == -1) {
      logfile(LOG_ERROR,
	      "notify_contents_except: bad next reference on object #%d\n",
	      list);
      return;
    }
  }
  if (!(nflags & NOT_NOAUDIBLE)) {
    if (get_int_elt(loc, EXITS, &list) == -1) {
      logfile(LOG_ERROR, "notify_contents_except: bad exits on object #%d\n",
	      loc);
      return;
    }
    while (list != -1) {
      if (isAUDIBLE(list) && (list != except))
	notify_audible(list, cause, sender, str);
      if (get_int_elt(list, NEXT, &list) == -1) {
	logfile(LOG_ERROR,
	        "notify_contents_except: bad next reference on object #%d\n",
	        list);
	return;
      }
    }
  }
}

void notify_contents_loc(loc, cause, sender, str, except, nflags)
    int loc, cause, sender;
    char *str;
    int except, nflags;
{
  int list;

  if (!has_contents(loc) || !str || !str[0])
    return;

  do {
    if (get_int_elt(loc, CONTENTS, &list) == -1) {
      logfile(LOG_ERROR,
	      "notify_contents_loc: bad contents list on object #%d\n",
	      list);
      return;
    }
    while (list != -1) {
      if ((except == -1) || (list != except)) {
	notify_player(list, cause, sender, str, nflags);
      }
      if (get_int_elt(list, NEXT, &list) == -1) {
	logfile(LOG_ERROR,
	        "notify_contents_loc: bad next reference on object #%d\n",
		list);
	return;
      }
    }
    if (!(nflags & NOT_NOAUDIBLE)) {
      if (get_int_elt(loc, EXITS, &list) == -1) {
	logfile(LOG_ERROR,
		"notify_contents_loc: bad exits list on object #%d\n", loc);
	return;
      }
      while (list != -1) {
	if (isAUDIBLE(list) && (list != except))
	  notify_audible(list, cause, sender, str);
	if (get_int_elt(list, NEXT, &list) == -1) {
	  logfile(LOG_ERROR,
	          "notify_contents_loc: bad next reference on object #%d\n",
		  list);
	  return;
	}
      }
    }
  }
  while (!isROOM(loc) && (get_int_elt(loc, LOC, &loc) != -1));
}

void notify_exits(player, cause, sender, list)
    int player, cause, sender, list;
{
  char *name, buffer[BUFFSIZ + 4], *p;
  int any = 0, bufsiz, dohtml;

  dohtml = has_html(player);

  p = buffer;
  bufsiz = sizeof(buffer) - 4;
  while (list != -1) {
    if (!isOBVIOUS(list)) {
      if (get_int_elt(list, NEXT, &list) == -1) {
	logfile(LOG_ERROR, "notify_exits: bad next reference on object #%d\n",
	        list);
	return;
      }
      continue;
    }
    any++;

    if (get_str_elt(list, NAME, &name) == -1) {
      logfile(LOG_ERROR, "notify_exits: bad name reference on object #%d\n",
	      list);
      return;
    }
    while ((name[0] == ' ') || (name[0] == ';'))
      name++;

    if (dohtml)
      name = html_anchor_exit(name);

    for (; *name && (*name != ';') && ((p - buffer) < bufsiz);
	 *p++ = *name++);
    if ((p - buffer) > bufsiz) {
      *p = '\0';
      break;
    }
    *p++ = ',';
    *p++ = ' ';

    if (get_int_elt(list, NEXT, &list) == -1) {
      logfile(LOG_ERROR, "notify_exits: bad next reference on object #%d\n",
	      list);
      return;
    }
  }
  if (any) {
    notify_player(player, cause, sender, "Obvious exits:", 0);

    if(p[-2] == ',')
      p[-2] = '\0';

    if(dohtml)
      notify_player(player, cause, sender, buffer, NOT_RAW);
    else
      notify_player(player, cause, sender, buffer, 0);
  }
}

void notify_list(player, cause, sender, list, flags)
    int player, cause, sender, list, flags;
{
  int count;
  int dohtml = has_html(player);

  if (dohtml)
    flags |= NOT_RAW;

  for (count = 0; (list != -1) && (count < mudconf.max_list); count++) {
    if (!(flags & NOT_DARKOK)) {
      if (!can_see(player, cause, list)) {	/* Skip this name */
	if (get_int_elt(list, NEXT, &list) == -1) {
	  logfile(LOG_ERROR, "notify_list: bad next reference on object #%d\n",
	          list);
	  break;
	}
	continue;
      }
    }

    if ((flags & NOT_DARKOK) || (list != player)) {
      if (dohtml) {
        char *name;

        if(get_str_elt(list, NAME, &name) == -1)
	  name = "???";

	notify_player(player, cause, sender,
		      html_anchor_contents(name,
					   display_name(player, cause, list)),
		      flags);
      } else {
        notify_player(player, cause, sender, display_name(player, cause, list),
		      flags);
      }
    }
    if (get_int_elt(list, NEXT, &list) == -1) {
      logfile(LOG_ERROR, "notify_list: bad next reference on object #%d\n",
	      list);
      break;
    }
  }
}

/* a combination of notify_exits() and notify_list(). */
void notify_list2(player, cause, sender, list, flags)
    int player, cause, sender, list, flags;
{
  char *name, buffer[BUFFSIZ + 4], *ptr;
  int count, bufsiz;
  int dohtml = has_html(player);

  if (dohtml)
    flags |= NOT_RAW;

  bufsiz = sizeof(buffer) - 4;
  ptr = buffer;
  for (count = 0; (list != -1) && (count < mudconf.max_list); count++) {
    if (!(flags & NOT_DARKOK)) {
      if (!can_see(player, cause, list)) {	/* Skip this name */
	if (get_int_elt(list, NEXT, &list) == -1) {
	  logfile(LOG_ERROR, "notify_list2: bad next reference on object #%d\n",
	          list);
	  break;
	}
	continue;
      }
    }

    if ((flags & NOT_DARKOK) || (list != player)) {
      if (dohtml) {
	char *sname;

        if(get_str_elt(list, NAME, &sname) == -1)
	  sname = "???";
	name = html_anchor_contents(sname, display_name(player, cause, list));
      } else
	name = display_name(player, cause, list);

      if (((ptr - buffer) + strlen(name)) > bufsiz) {
	/* Display what we have and continue. */
	if (ptr[-2] == ',')
	  ptr[-2] = '\0';
	notify_player(player, cause, sender, buffer, flags);

	ptr = buffer;
	goto nextlist;
      }

      for (; *name && ((ptr - buffer) < bufsiz); *ptr++ = *name++);
      if ((ptr - buffer) > bufsiz) {
	/* Opps, we overran it... */
        *ptr = '\0';
        break;
      }
      *ptr++ = ',';
      *ptr++ = ' ';
    }

nextlist:
    if (get_int_elt(list, NEXT, &list) == -1) {
      logfile(LOG_ERROR, "notify_list2: bad next reference on object #%d\n",
	      list);
      break;
    }
  }

  if (ptr > buffer) {
    if(ptr[-2] == ',')
      ptr[-2] = '\0';
    notify_player(player, cause, sender, buffer, flags);
  }
}