/* Cque.c */
#include <ctype.h>
#include <fcntl.h>
#include <string.h>
#ifdef XENIX
#include <sys/signal.h>
#else
#include <signal.h>
#endif /* xenix */
#include "config.h"
#include "db.h"
#include "interface.h"
#include "match.h"
#include "externs.h"
#ifdef MEM_CHECK
#include "mem_check.h"
#endif
#ifdef USE_NALLOC
#include "nalloc.h"
extern NALLOC *glurp;
NALLOC *big = NULL;
#endif
extern char ccom[];
extern dbref cplr;
extern int atoi();
typedef struct bque BQUE;
struct bque {
BQUE *next;
dbref player; /* player who will do command */
dbref cause; /* player causing command (for %N) */
int left; /* seconds left until execution */
char *env[10]; /* environment, from wild match */
char *comm; /* command to be executed */
};
static BQUE *qfirst = NULL, *qlast = NULL, *qwait = NULL;
static BQUE *qlfirst = NULL, *qllast = NULL;
void parse_que(player, command, cause)
dbref player;
char *command;
dbref cause; /* cause is needed to determine priority */
{
char buff[BUFFER_LEN], *s, *r;
void big_que();
s = buff;
strcpy(buff, command);
while (r = parse_up(&s, ';')) {
big_que(player, r, cause);
}
}
static int add_to(player, am)
dbref player;
int am;
{
int num = 0;
ATTR *a;
char buff[MAX_COMMAND_LEN];
player = db[player].owner;
a = atr_get(player, "QUEUE");
if(a)
num = atoi(a->value);
num += am;
if (num > 0)
sprintf(buff, "%d", num);
else
*buff = 0;
(void) atr_add(player, "QUEUE", buff, GOD, NOTHING);
return (num);
}
void big_que(player, command, cause)
dbref player;
char *command;
dbref cause;
{
int a;
BQUE *tmp;
#ifdef USE_NALLOC
if(!big)
big = na_open(sizeof(char));
#endif
if ((Typeof(player) != TYPE_PLAYER) && (db[player].flags & HALT))
return;
/* make sure player can afford to do it */
if (!payfor(player, QUEUE_COST + (((random() & QUEUE_LOSS) == 0) ? 1 : 0))) {
notify(db[player].owner, "Not enough money to queue command.");
return;
}
if (add_to(player, 1) > QUEUE_QUOTA) {
notify(db[player].owner, "Run away objects, commands halted");
do_halt(db[player].owner, "");
/* halt means no command execution allowed */
db[player].flags |= HALT;
return;
}
#ifdef USE_NALLOC
tmp = (BQUE *) na_alloc(big, sizeof(BQUE));
strcpy((tmp->comm = (char *) na_ualloc(big, strlen(command)+1)), command);
#else
tmp = (BQUE *) malloc (sizeof(BQUE));
strcpy((tmp->comm = (char *) malloc(strlen(command)+1)), command);
#endif
#ifdef MEM_CHECK
add_check("bqueue");
add_check("bqueue_comm");
#endif
tmp->player = player;
tmp->next = NULL;
tmp->left = 0;
tmp->cause = cause;
for (a = 0; a < 10; a++)
if (!wptr[a])
tmp->env[a] = NULL;
else {
#ifdef USE_NALLOC
strcpy((tmp->env[a] =(char *)na_ualloc(big, strlen(wptr[a])+1)),wptr[a]);
#else
strcpy((tmp->env[a] = (char *)malloc(strlen(wptr[a])+1)), wptr[a]);
#endif
#ifdef MEM_CHECK
add_check("bqueue_env");
#endif
}
if (Typeof(cause) == TYPE_PLAYER) {
if (qlast) {
qlast->next = tmp;
qlast = tmp;
} else
qlast = qfirst = tmp;
} else {
if (qllast) {
qllast->next = tmp;
qllast = tmp;
} else
qllast = qlfirst = tmp;
}
}
void wait_que(player, wait, command, cause)
dbref player;
int wait;
char *command;
dbref cause;
{
BQUE *tmp;
int a;
/* make sure player can afford to do it */
if (!payfor(player, QUEUE_COST + (((random() & QUEUE_LOSS) == 0) ? 1 : 0))) {
notify(player, "Not enough money to queue command.");
return;
}
#ifdef USE_NALLOC
tmp = (BQUE *) na_alloc(big, sizeof(BQUE));
strcpy((tmp->comm = (char *)na_ualloc(big, strlen(command)+1)), command);
#else
tmp = (BQUE *)malloc(sizeof(BQUE));
strcpy((tmp->comm = (char *)malloc(strlen(command)+1)), command);
#endif
#ifdef MEM_CHECK
add_check("bqueue");
add_check("bqueue_comm");
#endif
tmp->player = player;
tmp->next = qwait;
tmp->left = wait;
tmp->cause = cause;
for (a = 0; a < 10; a++)
if (!wptr[a])
tmp->env[a] = NULL;
else {
#ifdef USE_NALLOC
strcpy((tmp->env[a] = (char *)na_ualloc(big,strlen(wptr[a])+1)),wptr[a]);
#else
strcpy((tmp->env[a] = (char *)malloc(strlen(wptr[a])+1)), wptr[a]);
#endif
#ifdef MEM_CHECK
add_check("bqueue_env");
#endif
}
qwait = tmp;
}
/* call every second to check for wait queue commands */
void do_second()
{
BQUE *trail = NULL, *point, *next;
/* move contents of low priority queue onto end of normal one */
/* this helps to keep objects from getting out of control since */
/* its affects on other objects happen only after one seconds */
/* this should allow @halt to be type before getting blown away */
/* by scrolling text */
if (qlfirst) {
if (qlast)
qlast->next = qlfirst;
else
qfirst = qlfirst;
qlast = qllast;
qllast = qlfirst = NULL;
}
for (point = qwait; point; point = next)
/*
* Note: this would be 0 except the command is being put in the low
* priority queue to be done in one second anyways
*/
if (point->left-- <= 1) {
int a;
giveto(point->player, QUEUE_COST);
for (a = 0; a < 10; a++) {
wptr[a] = point->env[a];
}
parse_que(point->player, point->comm, point->cause);
if (trail)
trail->next = next = point->next;
else
qwait = next = point->next;
for (a = 0; a < 10; a++)
if (point->env[a]) {
#ifdef USE_NALLOC
na_unalloc(big, point->env[a]);
#else
free((char *)point->env[a]);
#endif
#ifdef MEM_CHECK
del_check("bqueue_env");
#endif
}
#ifdef USE_NALLOC
if (point->comm)
na_unalloc(big, point->comm);
na_unalloc(big, point);
#else
if (point->comm)
free((char *)point->comm);
free((char *)point);
#endif
#ifdef MEM_CHECK
del_check("bqueue_comm");
del_check("bqueue");
#endif
} else
next = (trail = point)->next;
}
int test_top()
{
return (qfirst ? 1 : 0);
}
/* execute one command off the top of the queue */
int do_top()
{
int a;
int i = 0;
BQUE *tmp;
dbref player;
char tbuf1[BUFFER_LEN], tbuf2[BUFFER_LEN];
char tbuf3[BUFFER_LEN], *s;
if (!qfirst)
return (0);
if (qfirst->player && !(db[qfirst->player].flags & GOING)) {
giveto(qfirst->player, QUEUE_COST);
cplr = qfirst->player;
strcpy(ccom, qfirst->comm);
add_to(player = qfirst->player, -1);
qfirst->player = 0;
if ((Typeof(player) == TYPE_PLAYER) || !(db[player].flags & HALT)) {
for (a = 0; a < 10; a++) {
wptr[a] = qfirst->env[a];
}
strcpy(tbuf2, uncompress(qfirst->comm));
tbuf3[0] = '\0';
for (s = tbuf2; *s; tbuf3[i++] = toupper(*s++)) ;
tbuf3[i++] = '\0';
if ((strstr(tbuf3, "@DOL")) == NULL)
strcpy(tbuf1, pronoun_substitute(qfirst->cause, tbuf2, player));
else
strcpy(tbuf1, tbuf2);
if (IS(player, TYPE_THING, THING_VERBOSE))
notify(db[player].owner, tprintf("#%d] %s", player, tbuf1));
process_command(player, tbuf1, qfirst->cause);
}
}
tmp = qfirst->next;
for (a = 0; a < 10; a++)
if (qfirst->env[a]) {
#ifdef USE_NALLOC
na_unalloc(big, qfirst->env[a]);
#else
free((char *) qfirst->env[a]);
#endif
#ifdef MEM_CHECK
del_check("bqueue_env");
#endif
}
#ifdef USE_NALLOC
if (qfirst->comm)
na_unalloc(big, qfirst->comm);
na_unalloc(big, qfirst);
#else
if (qfirst->comm)
free((char *)qfirst->comm);
free((char *)qfirst);
#endif
#ifdef MEM_CHECK
del_check("bqueue_comm");
del_check("bqueue");
#endif
if (!(qfirst = tmp))
qlast = NULL;
return (1);
}
/* tell player what commands they have pending in the queue */
void do_queue(player, what)
dbref player;
const char *what;
{
BQUE *tmp;
dbref victim = NOTHING;
int everything = 0;
int quick = 0;
int pq = 0, oq = 0, wq = 0;
int tpq = 0, toq = 0, twq = 0;
if (!string_compare(what, "count")) {
victim = player;
everything = 1;
quick = 1;
}
else if(Wizard(player)) {
if(!what || !*what)
victim = player;
else
if(!string_compare(what, "all")) { /* do the whole thing */
victim = player;
everything = 1;
} else {
init_match(player, what, TYPE_PLAYER);
match_player();
match_absolute();
match_me();
victim = match_result();
}
} else {
victim = player;
}
switch(victim) {
case NOTHING:
notify(player, "I couldn't find that player.");
break;
case AMBIGUOUS:
notify(player, "I don't know who you mean!");
break;
default:
if(everything == 1)
notify(player, "Queue for : all");
else
notify(player, tprintf("Queue for : %s", db[victim].name));
if (!quick) notify(player,"Player Queue:");
for (tmp = qfirst; tmp; tmp = tmp->next) {
tpq++;
if ((db[tmp->player].owner == db[victim].owner) || (everything)) {
pq++;
if (!quick)
notify(player, tprintf("%s:%s", unparse_object(player, tmp->player),
tmp->comm));
}
}
if (!quick) notify(player,"Object Queue:");
for (tmp = qlfirst; tmp; tmp = tmp->next) {
toq++;
if ((db[tmp->player].owner == db[victim].owner) || (everything)) {
oq++;
if (!quick)
notify(player, tprintf("%s:%s", unparse_object(player, tmp->player),
tmp->comm));
}
}
if (!quick) notify(player,"Wait Queue:");
for (tmp = qwait; tmp; tmp = tmp->next) {
twq++;
if ((db[tmp->player].owner == db[victim].owner) || (everything)) {
wq++;
if (!quick)
notify(player, tprintf("[%d]%s:%s", tmp->left,
unparse_object(player, tmp->player),
tmp->comm));
}
}
notify(player,"------------ Queue Done ------------");
notify(player,
tprintf("Totals: Player...%d/%d Object...%d/%d Wait...%d/%d",
pq, tpq, oq, toq, wq, twq));
}
}
/* remove all queued commands from a certain player */
/* it cannot be called on specific objects */
void do_halt(player, ncom)
dbref player;
char *ncom;
{
BQUE *tmp, *trail = NULL, *point, *next;
int num = 0;
notify(db[player].owner, "Halted.");
for (tmp = qfirst; tmp; tmp = tmp->next)
if ((tmp->player == player) || (db[tmp->player].owner == player)) {
num--;
giveto(player, QUEUE_COST);
tmp->player = 0;
}
for (tmp = qlfirst; tmp; tmp = tmp->next)
if ((tmp->player == player) || (db[tmp->player].owner == player)) {
num--;
giveto(player, QUEUE_COST);
tmp->player = 0;
}
/* remove wait q stuff */
for (point = qwait; point; point = next)
if ((point->player == player) || (db[point->player].owner == player)) {
int a;
giveto(player, QUEUE_COST);
if (trail)
trail->next = next = point->next;
else
qwait = next = point->next;
for (a = 0; a < 10; a++)
if (point->env[a]) {
#ifdef USE_NALLOC
na_unalloc(big, point->env[a]);
#else
free((char *)point->env[a]);
#endif
#ifdef MEM_CHECK
del_check("bqueue_env");
#endif
}
#ifdef USE_NALLOC
if (point->comm)
na_unalloc(big, point->comm);
na_unalloc(big, point);
#else
if (point->comm)
free((char *) point->comm);
free((char *) point);
#endif
#ifdef MEM_CHECK
del_check("bqueue_comm");
del_check("bqueue");
#endif
} else
next = (trail = point)->next;
if (db[player].owner == player)
(void) atr_add(player, "QUEUE", "", GOD, NOTHING);
else
add_to(player, num);
if (*ncom)
parse_que(player, ncom, player);
}
void do_halt1(player, arg1, arg2)
dbref player;
const char *arg1;
const char *arg2;
{
dbref victim;
char temp[BUFFER_LEN];
if (*arg1 == '\0')
do_halt(player, "");
else {
init_match(player, arg1, NOTYPE);
match_neighbor();
match_possession();
match_me();
match_absolute();
match_player();
if ((victim = noisy_match_result()) == NOTHING)
return;
if ((db[victim].owner != player) && (!Wizard(player))) {
notify(player, "Permission denied.");
return;
}
if (Typeof(victim) != TYPE_PLAYER) {
sprintf(temp, "#%d", victim);
do_set(player, temp, "HALT");
} else {
if (victim != player)
notify(player, "Halted.");
do_halt(victim, arg2);
}
}
}
void do_allhalt(player)
dbref player;
{
dbref victim;
if(!Wizard(player)) {
notify(player, "Sorry, you can only halt your own items.");
return;
}
for(victim = 0;victim <db_top; victim++) {
if(Typeof(victim) == TYPE_PLAYER) {
notify(victim,tprintf("Your objects have been globally halted by %s",
db[player].name));
do_halt(victim,"");
}
}
}