lotos123/
lotos123/datafiles/conffiles/
lotos123/datafiles/counters/
lotos123/datafiles/fonts/
lotos123/datafiles/helpfiles/
lotos123/datafiles/killmsgs/
lotos123/datafiles/mapfiles/
lotos123/datafiles/motds/motd1/
lotos123/datafiles/motds/motd2/
lotos123/datafiles/pictfiles/
lotos123/datafiles/plfiles/
lotos123/datafiles/plfiles/helpfiles/
lotos123/datafiles/screens/
lotos123/datafiles/textfiles/
lotos123/datafiles/trfiles/
lotos123/datafiles/votefiles/
lotos123/datafiles/votefiles/1/
lotos123/datafiles/votefiles/2/
lotos123/src/plugins/
lotos123/userfiles/
lotos123/userfiles/bin/
/* vi: set ts=4 sw=4 ai: */
/*
 * main.c
 *
 *   Lotos v1.2.3  : (c) 1999-2003 Pavol Hluchy (Lopo)
 *   last update   : 30.1.2003
 *   email         : lotos@losys.sk
 *   homepage      : lotos.losys.sk
 */
/*****************************************************************************
             Amnuts version 2.2.1 - Copyright (C) Andrew Collington
                       Last update: 3rd October, 1999

               amnuts@iname.com  |  http://www.talker.com/amnuts/

                        which is (heavily) modified

    NUTS version 3.3.3 (Triple Three :) - Copyright (C) Neil Robertson 1996
                      Last update: 18th November 1996
******************************************************************************
    NUTS version 3.3.3 (Triple Three :) - Copyright (C) Neil Robertson 1996
                     Last update: 18th November 1996

 This software is provided as is. It is not intended as any sort of bullet
 proof system for commercial operation (though you may use it to set up a 
 pay-to-use system, just don't attempt to sell the code itself) and I accept 
 no liability for any problems that may arise from you using it. Since this is 
 freeware (NOT public domain , I have not relinquished the copyright) you may 
 distribute it as you see fit and you may alter the code to suit your needs.

 Read the COPYRIGHT file for further information.

 Neil Robertson. 

 Email    : neil@ogham.demon.co.uk
 Home page: http://www.wso.co.uk/neil.html (need JavaScript enabled browser)
 NUTS page: http://www.wso.co.uk/nuts.html
 Newsgroup: alt.talkers.nuts

 NB: This program listing looks best when the tab length is 5 chars which is
 "set ts=5" in vi.

 *****************************************************************************/
/*****************************************************************************
     MAIN CODE - MAIN CODE - MAIN CODE - MAIN CODE - MAIN CODE - MAIN CODE
 *****************************************************************************/

#ifndef __MAIN_C__
#define __MAIN_C__ 1

#include <stdio.h>
#ifdef _AIX
#include <sys/select.h> 
#endif
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <time.h>
#include <netdb.h>
#include <netinet/in.h>
#include <signal.h>
#include <unistd.h>
#include <setjmp.h>
#include <errno.h>
#include <sys/file.h>
#include <dirent.h>
#include <stddef.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <arpa/inet.h>
#include <arpa/telnet.h>

#include "define.h"
#include "prototypes.h"

/* The following ifdef must be made after all of the above.
   I have had a number of requests to seperate the Amnuts code into smaller
   files and also to take out the Netlink functions.  This is a compromise.
   Whereas there is no makefile, so you have to always recompile everything,
   it is an easy way to seperate up the code.  And by using ifdef for the
   Netlinks you can compile without any Netlink functionality.
   I will openly admit that this is a bit of a hack way of doing it.  If you
   don't like the way this is done, then I don't really care :-)
*/
#ifdef NETLINKS
	#include "obj_nl.h"
#endif

/* ostatne treba vzdy */
#include "obj_sys.h"
#include "obj_syspp.h"

#include "main.h"
#include "commands.h"
#include "val_ign.h"


/******************************************************************************
 The setting up of the talker configs and the main program loop
 *****************************************************************************/
int main(int argc,char *argv[])
{
	fd_set readmask; 
	int i, len;
	char inpstr[ARR_SIZE];
	UR_OBJECT user,next;
#ifdef NETLINKS
	NL_OBJECT nl;
#endif

	strcpy(progname, argv[0]);
	if (argc<2) strcpy(confile, CONFIGFILE);
	else strcpy(confile, argv[1]);

/* Run in background automatically. */
/* moved here because of .reboot wasn't working properly with the forking after
   the rest of the initiation had taken place.
   */
#ifndef DEBUG
	switch (fork()) {
		case -1: boot_exit(11);  /* fork failure */
		case  0: break; /* child continues */
		default: sleep(1); exit(0);  /* parent dies */
		}
#endif

/* Startup and do initial counts and parses */
#ifdef DEBUG
	crash_step=0;
#endif
	create_system();
	create_systempp();
	set_date_time();
	init_signals();
	write_syslog(SYSLOG,0,"------------------------------------------------------------------------------\nSERVER BOOTING\n");
	printf("\n------------------------------------------------------------------------------\n");
	printf("%s %s server boot %s\n", reg_sysinfo[TALKERNAME], TVERSION, long_date(1));
	printf("Lotos system v%s\n", OSSVERSION);
	printf("------------------------------------------------------------------------------\n");
	printf("Systemove meno : %s, release %s, %s\n",amsys->sysname,amsys->sysrelease,amsys->sysversion);
	printf("Spustene na    : %s, %s\n",amsys->sysmachine,amsys->sysnodename);
#ifndef NETLINKS
	printf("Netlinky       : Zakazane\n");
#else
	printf("Netlinky       : Povolene\n");
#endif
	load_and_parse_config();

	printf("Flood ochrana je %s.\n", offon[amsys->flood_protect]);
	if (amsys->personal_rooms) {
		if (amsys->startup_room_parse) parse_user_rooms();
		else printf("Osobne miestnosti su aktivne, ale neskontrolovane pri boote.\n");
		}
	else printf("Osobne miestnosti zakazane.\n");
	printf("Kontrolujem strukturu user adresarov\n"); check_directories();
	printf("Processing user list\n"); process_users();
	printf("Pocitam userov\n"); count_users();
	printf("Rozbor struktury prikazov\n"); parse_commands();

	purge(0,NULL,0);
	if (!amsys->auto_purge) printf("PURGE: Auto-purge je vyp.\n");
	else printf("PURGE: Checked %d user%s, %d %s deleted due to lack of use.\n",
		amsys->purge_count,PLTEXT_S(amsys->purge_count),amsys->users_purged,
		PLTEXT_WAS(amsys->users_purged));

	check_messages(NULL,1);
	count_suggestions();
	printf("There %s %d suggestion%s.\n",PLTEXT_WAS(amsys->suggestion_count),amsys->suggestion_count,PLTEXT_S(amsys->suggestion_count));
	count_motds(0);
	printf("There %s %d login motd%s and %d post-login motd%s\n",
		PLTEXT_WAS(amsys->motd1_cnt),amsys->motd1_cnt,PLTEXT_S(amsys->motd1_cnt),amsys->motd2_cnt,
		PLTEXT_S(amsys->motd2_cnt));

/* open the talker after everything else has parsed */
	if (!strcmp(argv[argc-1], "-reinit")) reinit_sockets();
	else init_sockets();
	init_hostsfile();
#ifdef NETLINKS
	if (amsys->auto_connect) init_connections();
	else printf("Preskakujem pripajaciu cast.\n");
#endif

/* finish off the boot-up process */
	reset_alarm();
	lotos_load();
	load_counters();
	reloads(NULL);
	load_swear_file(NULL);
	if (!strcmp(argv[argc-1], "-reinit")) restore_structs();
#ifndef DEBUG
	clear_temps();
#endif
	create_kill_file();
	printf("------------------------------------------------------------------------------\n");
	printf("Nabootovane s PID %u\n",amsys->pid);
	printf("------------------------------------------------------------------------------\n\n");
	write_syslog(SYSLOG,0,"------------------------------------------------------------------------------\n");
	write_syslog(SYSLOG,0,"SERVER BOOTED with PID %u %s\n",amsys->pid,long_date(1));
	write_syslog(SYSLOG,0,"------------------------------------------------------------------------------\n\n");

	write_pid();

/******************************************************************************
 Main program loop
 *****************************************************************************/
	setjmp(jmpvar); /* jump to here if we crash and crash_action = IGNORE */
	while (1) {
  /* set up mask then wait */
		setup_readmask(&readmask);
		if (select(FD_SETSIZE,&readmask,0,0,0)==-1) continue;
  /* check for connection to listen sockets */
		for (i=0;i<port_total;++i) {
			if (FD_ISSET(listen_sock[i],&readmask))
				accept_connection(listen_sock[i],i);
			}
#ifdef NETLINKS
    /* Cycle through client-server connections to other talkers */
		for (nl=nl_first;nl!=NULL;nl=nl->next) {
			no_prompt=0;
			if (nl->type==UNCONNECTED || !FD_ISSET(nl->socket,&readmask)) continue;
      /* See if remote site has disconnected */
			if (!(len=read(nl->socket,inpstr,sizeof(inpstr)-3))) {
				write_syslog(NETLOG,1,"NETLINK: Remote disconnect by %s.\n",
					(nl->stage==UP)?nl->service:nl->site);
				vwrite_room(NULL,"~OLSYSTEM:~RS Stratena linka %s v %s.\n",
					nl->service,nl->connect_room->name);
				shutdown_netlink(nl);
				continue;
				}
			inpstr[len]='\0'; 
			exec_netcom(nl,inpstr);
			}
#endif
  /* Cycle through users. Use a while loop instead of a for because
     user structure may be destructed during loop in which case we
     may lose the user->next link. */
		user=user_first;
		while (user!=NULL) {
			next=user->next; /* store in case user object is destructed */
    /* If remote user or clone ignore */
			if (user->type!=USER_TYPE) {  user=next;  continue; }
    /* see if any data on socket else continue */
			if (!FD_ISSET(user->socket,&readmask)) { user=next;  continue; }
    /* see if client (eg telnet) has closed socket */
			inpstr[0]='\0';
			if (!(len=read(user->socket, inpstr, sizeof(inpstr)))) {
				disconnect_user(user);
				user=next;
				continue;
				}
    /* ignore control code replies */
			if ((unsigned char)inpstr[0]==255) {
				user=next;
				continue;
				}
    /* Deal with input chars. If the following if test succeeds we
       are dealing with a character mode client so call function. */
			if (inpstr[len-1]>=32 || user->buffpos) {
				if (get_charclient_line(user,inpstr,len)) goto GOT_LINE;
				user=next;
				continue;
				}
			else terminate(inpstr);

GOT_LINE:
			no_prompt=0;  
			com_num=-1;
			force_listen=0; 
			destructed=0;
			user->buff[0]='\0';  
			user->buffpos=0;
			user->last_input=time(0);
			if (user->login>0) {
				login(user,inpstr);
				user=next;
				continue;
				}
    /* If a dot on its own then execute last inpstr unless its a misc
       op or the user is on a remote site */
			if (!user->misc_op) {
				if (!strcmp(inpstr,".") && user->inpstr_old[0] && user->level>GOD) {
					strcpy(inpstr,user->inpstr_old);
					vwrite_user(user,"%s\n",inpstr);
					}
      /* else save current one for next time */
				else {
					if (inpstr[0]) strncpy(user->inpstr_old,inpstr,REVIEW_LEN);
					}
				}
    /* Main input check */
			clear_words();
			if (!user->misc_op && !user->edit_op && user->set_mode==SET_NONE) {
				if (!check_macros(user,inpstr)) {
					prompt(user);
					user=next;
					continue;
					}
				}
			clear_words();
			word_count=wordfind(inpstr);
			if (user->afk) {
				if (user->afk==2) {
					user->tmp_int=user->terminal.blind;
					user->terminal.blind=0;
					if (!word_count) {
						if (user->command_mode) prompt(user);
						user->terminal.blind=user->tmp_int;
						user=next;
						continue;
						}
					if (!strcmp(word[0], "who")) {
						who(user, 0);
						user->terminal.blind=user->tmp_int;
						user=next;
						continue;
						}
					if (strcmp((char *)crypt(word[0],crypt_salt),user->pass)) {
						write_user(user, password_bad);
						prompt(user);
						user->terminal.blind=user->tmp_int;
						user=next;
						continue;
						}
					echo_on(user);
					cls(user);
					user->terminal.blind=0;
					write_user(user,"Session unlocked, you are no longer AFK.\n");
					}
				else write_user(user,"You are no longer AFK.\n");  
				user->afk_mesg[0]='\0';
				if (user->afkbuff[0].buff[0]) revafk(user);
				if (user->vis) vwrite_room_except(user->room,user,"%s~RS comes back from being AFK.\n",user->recap);
				if (user->afk==2) {
					user->afk=0;
					user->status='a';
					prompt(user);
					user=next;
					continue;
					}
				user->afk=0;
				user->status='a';
				}
			if (!word_count) {
				if (misc_ops(user,inpstr))  {  user=next;  continue;  }
				if (setops(user,inpstr))  {  user=next;  continue;  }
#ifdef NETLINKS
				if (user->room==NULL) {
					sprintf(text,"ACT %s NL\n",user->name);
					write_sock(user->netlink->socket,text);
					}
#endif
				prompt(user);
				user=next;  continue;
				}
			if (misc_ops(user,inpstr))  {  user=next;  continue;  }
			if (setops(user,inpstr))  {  user=next;  continue;  }
			com_num=-1;
			if (user->command_mode || strchr(".>;:</&![@'*+-,?#",inpstr[0])) exec_com(user,inpstr);
			else
#ifdef PUEBLO
				if (!(chck_pblo(user, inpstr)))
#endif
					say(user,inpstr);
			if (!destructed) {
				if (user->room!=NULL && !destructed) prompt(user); 
				else {
					switch (com_num) {
	  /* case -1  :  Not in enumerated values - Unknown command */
#ifdef NETLINKS
						case HOME:
#endif
						case QUIT:
						case SUICIDE:
						case REBOOT:
						case SHUTDOWN: prompt(user);
						default: break;
						}
					}
				}
			user=next;
			} /* end while(user) */
		} /* end while(1) */
} /* main */


/******************************************************************************
 String functions - comparisons, convertions, etc
 *****************************************************************************/
/* tieto dve funkcie tu zostali kvoli NUM_COLS */

/*** Count the number of colour commands in a string ***/
int colour_com_count(char *str)
{
	char *s=str;
	int i,cnt=0;

	set_crash();
	while (*s) {
		if (*s=='~') {
			++s;
			for (i=0;i<NUM_COLS;++i) {
				if (!strncmp(s,colour_codes[i].txt_code,2)) {
					cnt++;
					s++;
					break;
					}
				}
			continue;
			}
		++s;
		}
	return cnt;
}


/*** Strip out colour commands from string for when we are sending strings
     over a netlink to a talker that doesn't support them ***/
char *colour_com_strip(char *str)
{
	char *s=str, *t;
	static char text2[ARR_SIZE];
	int i;

	set_crash();
	t=text2;
	while (*s) {
		if (*s=='~') {
			++s;
			for (i=0;i<NUM_COLS;++i) {
				if (!strncmp(s,colour_codes[i].txt_code,2)) {
					s++;
					goto CONT_M;
					}
				}
			--s;
			*t++=*s;
			}
		else *t++=*s;
CONT_M:
		s++;
		}
	*t='\0';
	return text2;
}


/******************************************************************************
 Object functions
 *****************************************************************************/

/*** Construct user/clone object ***/
UR_OBJECT create_user(void)
{
	UR_OBJECT user;

	set_crash();
	if ((user=(UR_OBJECT)malloc(sizeof(struct user_struct)))==NULL) {
		write_syslog(ERRLOG,1,"Memory allocation failure in create_user().\n");
		return NULL;
		}
/* Append object into linked list. */
	if (user_first==NULL) {  
		user_first=user;
		user->prev=NULL;  
		}
	else {  
		user_last->next=user;
		user->prev=user_last;  
		}
	user->next=NULL;
	user_last=user;

/* initialise user structure */
	user->type=USER_TYPE;
	user->socket=-1;
	user->attempts=0;
	user->login=0;
	user->port=0;
	user->site_port=0;
	user->name[0]='\0';
	user->site[0]='\0';
	reset_user(user);
	return user;
}


/* reset the user variables */
void reset_user(UR_OBJECT user)
{
int i;

	set_crash();
strcpy(user->email,"#UNSET");
strcpy(user->homepage,"#UNSET");
strcpy(user->verify_code,"#NONE");
strcpy(user->version,USERVER);
user->recap[0]='\0';
user->bw_recap[0]='\0';
strcpy(user->desc, default_desc);
strcpy(user->in_phrase, default_inphr);
strcpy(user->out_phrase, default_outphr);
user->afk_mesg[0]='\0';
user->pass[0]='\0';
user->last_site[0]='\0';
user->page_file[0]='\0';
user->mail_to[0]='\0';
user->inpstr_old[0]='\0';
user->buff[0]='\0'; 
user->call[0]='\0';
user->samesite_check_store[0]='\0';
user->invite_by[0]='\0';
strcpy(user->logout_room,room_first->name);
strcpy(user->date,(long_date(1)));
strcpy(user->icq,"#UNSET");
for (i=0; i<MAX_IGNORES; ++i) user->ignoreuser[i][0]='\0';
for (i=0;i<MAX_COPIES;++i) user->copyto[i][0]='\0';
for (i=0;i<MAX_FRIENDS;++i) user->friend[i][0]='\0';
for (i=0;i<REVTELL_LINES;++i) {
	user->afkbuff[i].buff[0]='\0';
	user->afkbuff[i].time=0;
	}
for (i=0;i<REVTELL_LINES;++i) {
	user->editbuff[i].buff[0]='\0';
	user->editbuff[i].time=0;
	}
for (i=0;i<REVTELL_LINES;++i) {
	user->revbuff[i].buff[0]='\0';
	user->revbuff[i].time=0;
	}
#ifdef NETLINKS
 user->netlink=NULL;
 user->pot_netlink=NULL; 
#endif
user->room=NULL;
user->invite_room=NULL;
user->malloc_start=NULL;
user->malloc_end=NULL;
user->owner=NULL;
user->wrap_room=NULL;
user->t_expire=time(0)+(NEWBIE_EXPIRES*86400);
user->read_mail=time(0);
user->last_input=time(0);
user->last_login=time(0);
user->level=NEW;
user->real_level=user->level;
user->unarrest=NEW;
user->arrestby=0;
user->buffpos=0;
user->filepos=0;
user->command_mode=0;
user->vis=1;
user->muzzled=0;
user->remote_com=-1;
user->last_login_len=0;
user->total_login=0;
user->prompt=amsys->prompt_def;
user->misc_op=0;
user->edit_op=0;
user->edit_line=0;
user->charcnt=0;
user->warned=0;
user->accreq=0;
user->afk=0;
user->revline=0;
user->clone_hear=CLONE_HEAR_ALL;
user->wipe_to=0;
user->wipe_from=0;
user->logons=0;
user->expire=1;
user->lroom=0;
user->monitor=0;
user->gender=NEUTER;
user->age=0;
user->hideemail=1;
user->misses=0;
user->hits=0;
user->kills=0;
user->deaths=0;
user->bullets=6;
user->hps=10;
user->alert=0;
user->mail_verified=0;
user->autofwd=0;
user->editing=0;
user->hwrap_lev=0;
user->afkline=0;
user->editline=0;
user->show_pass=0;
user->samesite_all_store=0;
user->hwrap_id=0;
user->hwrap_same=0;
user->hwrap_func=0;
user->cmd_type=1;
user->show_rdesc=1;
user->lmail_lev=-3; /* has to be -3 */
for (i=0;i<MAX_REMINDERS;i++) {
  user->reminder[i].day=0;
  user->reminder[i].month=0;
  user->reminder[i].year=0;
  user->reminder[i].msg[0]='\0';
  }
user->temp_remind.day=0;
user->temp_remind.month=0;
user->temp_remind.year=0;
user->temp_remind.msg[0]='\0';
for (i=0;i<MAX_XCOMS;i++) user->xcoms[i]=-1;
for (i=0;i<MAX_GCOMS;i++) user->gcoms[i]=-1;
for (i=0;i<MAX_PAGES;i++) user->pages[i]=0;
user->pagecnt=0;
user->user_page_pos=0;
user->user_page_lev=0;
user->tmp_int=0;
user->first_macro=NULL;
user->last_macro=NULL;
user->prompt_str[0]='\0';
user->ltell[0]='\0';
user->nameg[0]='\0';
user->named[0]='\0';
user->namea[0]='\0';
user->namel[0]='\0';
user->namei[0]='\0';
#ifdef PUEBLO
user->pueblo=0;
user->pueblo_mm=0;
user->pueblo_pg=0;
user->voiceprompt=1;
user->pblodetect=1;
#endif
user->alarm=0;
user->atime=0;
reset_murlist(user);
user->restrict[0]='\0';
user->ign_word=NULL;
user->auth_addr=0;
user->set_mode=SET_NONE;
user->set_op=0;
user->who_type=1;
user->status='a';
user->terminal.bckg=0;
user->terminal.txt=0;
user->terminal.revers=0;
user->terminal.blink=0;
user->terminal.bold=0;
user->terminal.underline=0;
user->terminal.clear=0;
user->terminal.music=0;
user->terminal.xterm=0;
user->terminal.checho=amsys->charecho_def;
user->terminal.wrap=0;
user->terminal.blind=0;
user->terminal.pager=23;
user->ignore.all=0;
user->ignore.all_store=0;
user->ignore.tells=0;
user->ignore.logons=0;
user->ignore.shouts=0;
user->ignore.pics=0;
user->ignore.wiz=0;
user->ignore.greets=0;
user->ignore.beeps=0;
user->ignore.transp=0;
user->ignore.funs=0;
user->money=DEFAULT_MONEY;
user->bank=DEFAULT_BANK;
user->inctime=0;
user->kradnutie=0;
user->lynx=0;
user->follow[0]='\0';
user->next_ping=PINGINTERVAL;
user->last_ping=-1;
}


/*** Destruct an object. ***/
void destruct_user(UR_OBJECT user)
{
	set_crash();
/* Remove from linked list */
	if (user==user_first) {
		user_first=user->next;
		if (user==user_last) user_last=NULL;
		else user_first->prev=NULL;
		}
	else {
		user->prev->next=user->next;
		if (user==user_last) { 
			user_last=user->prev;
			user_last->next=NULL; 
			}
		else user->next->prev=user->prev;
		}
	free(user);
	destructed=1;
}


/*** Construct room object ***/
RM_OBJECT create_room(void)
{
	RM_OBJECT room;
	int i;

	set_crash();
	if (!(room=(RM_OBJECT)malloc(sizeof(struct room_struct)))) {
		fprintf(stderr,"Lotos: Memory allocation failure in create_room().\n");
		boot_exit(1);
		}
	/* Append object into linked list. */
	if (room_first==NULL) {  
		room_first=room;
		room->prev=NULL;  
		}
	else {  
		room_last->next=room;
		room->prev=room_last;
		}
	room->next=NULL;
	room_last=room;

	room->name[0]='\0';
	room->label[0]='\0';
	room->desc[0]='\0';
	room->topic[0]='\0';
	room->map[0]='\0';
	room->access=-1;
	room->revline=0;
	room->mesg_cnt=0;
	room->transp=NULL;
	strcpy(room->topicowner, "~CRSYSTEM~RS");
	room->topiclock=0;
#ifdef NETLINKS
	room->inlink=0;
	room->netlink=NULL;
	room->netlink_name[0]='\0';
#endif
	room->next=NULL;
	for (i=0;i<MAX_LINKS;++i) {
		room->link_label[i][0]='\0';
		room->link[i]=NULL;
		}
	for (i=0;i<REVIEW_LINES;++i) {
		room->revbuff[i].buff[0]='\0';
		room->revbuff[i].time=0;
		}
	return room;
}


/*** Destruct a room object. ***/
void destruct_room(RM_OBJECT rm) {
/* Remove from linked list */
	if (rm==room_first) {
		room_first=rm->next;
		if (rm==room_last) room_last=NULL;
		else room_first->prev=NULL;
		}
	else {
		rm->prev->next=rm->next;
		if (rm==room_last) { 
			room_last=rm->prev;
			room_last->next=NULL; 
			}
		else rm->next->prev=rm->prev;
		}
	if (rm->transp!=NULL) destruct_transport(rm->transp);
	free(rm);
}


/* add a command to the commands linked list.  Get which command via the passed id
   int and the enum in the header file */
int add_command(int cmd_id)
{
	int inserted;
	struct command_struct *cmd,*tmp;

	set_crash();
if ((cmd=(struct command_struct *)malloc(sizeof(struct command_struct)))==NULL) {
  write_syslog(ERRLOG,1,"Memory allocation failure in add_command().\n");
  return 0;
  }

/* 
   do an insertion sort on the linked list
   this could take a long time, but it only needs to be done once when booting, so it
   doesn't really matter
*/

inserted=0;
strcpy(cmd->name,command_table[cmd_id].name);
if (first_command==NULL) {
  first_command=cmd;
  cmd->prev=NULL;
  cmd->next=NULL;
  last_command=cmd;
  }
else {
  tmp=first_command;
  inserted=0;
  while(tmp!=NULL) {
    /* insert as first item in the list */
    if ((strcmp(cmd->name,tmp->name)<0) && tmp==first_command) {
      first_command->prev=cmd;
      cmd->prev=NULL;
      cmd->next=first_command;
      first_command=cmd;
      inserted=1;
      }
    /* insert in the middle of the list somewhere */
    else if (strcmp(cmd->name,tmp->name)<0) {
      tmp->prev->next=cmd;
      cmd->prev=tmp->prev;
      tmp->prev=cmd;
      cmd->next=tmp;
      inserted=1;
      }
    if (inserted) break;
    tmp=tmp->next;
    } /* end while */
  /* insert at the end of the list */
  if (!inserted) {
    last_command->next=cmd;
    cmd->prev=last_command;
    cmd->next=NULL;
    last_command=cmd;
    }
  } /* end else */

cmd->id=cmd_id;
strcpy(cmd->alias,command_table[cmd_id].alias);
cmd->min_lev=command_table[cmd_id].level;
cmd->function=command_table[cmd_id].function;
cmd->count=0;
return 1;
}


/* destruct command nodes */
int rem_command(int cmd_id)
{
	struct command_struct *cmd=first_command;

	set_crash();
/* as command object not being passed, first find what node we want to delete
   for the id integer that *is* passed.
   */
	while(cmd!=NULL) {
		if (cmd->id==cmd_id) break;
		cmd=cmd->next;
		}
	if (cmd==first_command) {
		first_command=cmd->next;
		if (cmd==last_command) last_command=NULL;
		else first_command->prev=NULL;
		}
	else {
		cmd->prev->next=cmd->next;
		if (cmd==last_command) { 
			last_command=cmd->prev;
			last_command->next=NULL; 
			}
		else cmd->next->prev=cmd->prev;
		}
	free(cmd);
	return 1;
}


/* add a user node to the user linked list */
int add_user_node(char *name, int level)
{
	struct user_dir_struct *new;

	set_crash();
if ((new=(struct user_dir_struct *)malloc(sizeof(struct user_dir_struct)))==NULL) {
  write_syslog(ERRLOG,1,"Memory allocation failure in add_user_node().\n");
  return 0;
  }
if (first_dir_entry==NULL) {
  first_dir_entry=new;
  new->prev=NULL;
  }
else {
  last_dir_entry->next=new;
  new->prev=last_dir_entry;
  }
new->next=NULL;
last_dir_entry=new;

++amsys->user_count;
strcpy(new->name,name);
new->level=level;
new->date[0]='\0';
return 1;
}


/* remove a user node from the user linked list
   have needed to use an additional check for the correct user, ie, lev.
   if lev = -1 then don't do a check on the user node's level, else use
   the lev and the name as a check
   */
int rem_user_node(char *name, int lev)
{
	int level, found=0;
	struct user_dir_struct *entry=first_dir_entry;

	set_crash();
if (lev!=-1) {
  while(entry!=NULL) {
    if ((!strcmp(entry->name,name)) && (entry->level==lev)) {
      level=entry->level;  found=1;  break;
      }
    entry=entry->next;
    }
  }
else {
  while(entry!=NULL) {
    if (!strcmp(entry->name,name)) {
      level=entry->level;  found=1;  break;
      }
    entry=entry->next;
    }
  }
if (!found) return 0;
if (entry==first_dir_entry) {
  first_dir_entry=entry->next;
  if (entry==last_dir_entry) last_dir_entry=NULL;
  else first_dir_entry->prev=NULL;
  }
else {
  entry->prev->next=entry->next;
  if (entry==last_dir_entry) { 
    last_dir_entry=entry->prev;  last_dir_entry->next=NULL; 
    }
  else entry->next->prev=entry->prev;
  }
free(entry);
--amsys->user_count;
return 1;
}


/* put a date string in a node in the directory linked list that
   matches name
   */
void add_user_date_node(char *name, char *date)
{
	struct user_dir_struct *entry;

	set_crash();
	for (entry=first_dir_entry; entry!=NULL; entry=entry->next) {
		if (!strcmp(entry->name,name)) {
			strcpy(entry->date,date);
			break;
			}
		}
	return;
}


/* add a node to the wizzes linked list */
int add_wiz_node(char *name, int level)
{
	struct wiz_list_struct *new;

	set_crash();
if ((new=(struct wiz_list_struct *)malloc(sizeof(struct wiz_list_struct)))==NULL) {
  write_syslog(ERRLOG,1,"Memory allocation failure in add_wiz_node().\n");
  return 0;
  }
if (first_wiz_entry==NULL) {
  first_wiz_entry=new;
  new->prev=NULL;
  }
else {
  last_wiz_entry->next=new;
  new->prev=last_wiz_entry;
  }
new->next=NULL;
last_wiz_entry=new;

strcpy(new->name,name);
new->level=level;
return 1;
}


/* remove a node from the wizzes linked list
   have needed to use an additional check for the correct user, ie, lev.
   if lev = -1 then don't do a check on the user node's level, else use
   the lev and the name as a check
   */
int rem_wiz_node(char *name)
{
	int level, found=0;
	struct wiz_list_struct *entry=first_wiz_entry;

	set_crash();
while(entry!=NULL) {
  if (!strcmp(entry->name,name)) {
    level=entry->level;  found=1;  break;
    }
  entry=entry->next;
  }
if (!found) return 0;
if (entry==first_wiz_entry) {
  first_wiz_entry=entry->next;
  if (entry==last_wiz_entry) last_wiz_entry=NULL;
  else first_wiz_entry->prev=NULL;
  }
else {
  entry->prev->next=entry->next;
  if (entry==last_wiz_entry) { 
    last_wiz_entry=entry->prev;  last_wiz_entry->next=NULL; 
    }
  else entry->next->prev=entry->prev;
  }
free(entry);
return 1;
}


/*** alter the level of a node in the user linked list ***/
int user_list_level(char *name, int lvl)
{
	struct user_dir_struct *entry=first_dir_entry;

	set_crash();
	while(entry!=NULL) {
		if (!strcmp(entry->name,name)) {
			entry->level=lvl;
			return(1);
			}
		entry=entry->next;
		}
	return(0);
}



/******************************************************************************
 Perfom checks and searches
 *****************************************************************************/


/*** Check to see if the pattern 'pat' appears in the string 'str'.
     Uses recursion to acheive this 
     ***/
int pattern_match(char *str, char *pat)
{
	int  i, slraw;

/* if end of both, strings match */
	if ((*pat=='\0') && (*str=='\0')) return(1);
	if (*pat=='\0') return(0);
	if (*pat=='*') {
		if (*(pat+1)=='\0') return(1);
		for (i=0, slraw=strlen(str); i<=slraw; i++)
			if ((*(str+i)==*(pat+1)) || (*(pat+1)=='?'))
				if (pattern_match(str+i+1,pat+2)==1) return(1);
		} /* end if */
	else {
		if (*str=='\0') return(0);
		if ((*pat=='?') || (*pat==*str))
			if (pattern_match(str+1,pat+1)==1) return(1);
		} /* end else */
	return(0); 
}


/*** See if users site is banned ***/
int site_banned(char *sbanned, int new)
{
	FILE *fp;
	char line[82], fname[FNAME_LEN];

if (new) strcpy(fname, NEWBAN);
else strcpy(fname, SITEBAN);
if (!(fp=fopen(fname,"r"))) return (0);
fscanf(fp,"%s",line);
while(!feof(fp)) {
  /* first do full name comparison */
  if (!strcmp(sbanned,line)) {  fclose(fp);  return 1;  }
  /* check using pattern matching */
  if (pattern_match(sbanned,line)) {
    fclose(fp);
    return(1);
    }
  fscanf(fp,"%s",line);
  }
fclose(fp);
return(0);
}


/*** checks to see if someone is already in login-stage on the ports ***/
int login_port_flood(char *asite)
{
	UR_OBJECT u;
	int cnt=0;

	set_crash();
	for (u=user_first;u!=NULL;u=u->next)
		if (u->login && (!strcmp(asite,u->site) || !strcmp(asite,u->ipsite))) cnt++;
	if (cnt>=LOGIN_FLOOD_CNT) return 1;
	return 0;
}


/*** See if user is banned ***/
int user_banned(char *name)
{
	FILE *fp;
	char line[82];

	if (!(fp=fopen(USERBAN, "r"))) return 0;
	fscanf(fp,"%s",line);
	while (!feof(fp)) {
		if (!strcmp(line,name)) {
			fclose(fp);
			return 1;
			}
		fscanf(fp,"%s",line);
		}
	fclose(fp);
	return 0;
}


/*** Set room access back to public if not enough users in room ***/
void reset_access(RM_OBJECT rm)
{
	UR_OBJECT u;
	int cnt=0;

if (rm==NULL || rm->access!=PRIVATE) return; 
for(u=user_first;u!=NULL;u=u->next) if (u->room==rm) ++cnt;
if (cnt<amsys->min_private_users) {
  write_room(rm,"Pristup do ruumy vrateny na ~FGPUBLIC.\n");
  rm->access=PUBLIC;
  /* Reset any invites into the room & clear review buffer */
  for(u=user_first;u!=NULL;u=u->next) {
    if (u->invite_room==rm) u->invite_room=NULL;
    }
  clear_revbuff(rm);
  }
}


/*** Get user struct pointer from name ***/
UR_OBJECT get_user(char *name)
{
	UR_OBJECT u;

	name[0]=toupper(name[0]);
/* Search for exact name */
	for(u=user_first;u!=NULL;u=u->next) {
		if (u->login || u->type==CLONE_TYPE) continue;
		if (!strcmp(u->name,name))  return u;
		}
	return NULL;
}


/*** Get user struct pointer from abreviated name ***/
UR_OBJECT get_user_name(UR_OBJECT user, char *i_name)
{
	UR_OBJECT u=NULL, last=NULL;
	int found=0;
	char name[USER_NAME_LEN+1], buff[ARR_SIZE];

strncpy(name, i_name, USER_NAME_LEN);
name[0]=toupper(name[0]);
buff[0]='\0';
if ((u=get_user(name))!=NULL) return u;
for (u=user_first;u!=NULL;u=u->next)
  if (!strcmp(u->name,name) && u->room!=NULL) return u;
for (u=user_first;u!=NULL;u=u->next) {
  if (u->type==CLONE_TYPE) continue;
    if (s_instr(u->name,name) != -1) {
      strcat(buff,u->name);
      strcat(buff, "  ");
      found++;
      last=u;
      }
  } /* end for */
if (found == 0) return NULL;
if (found >1) {
  write_user(user, "~FR~OLMeno nie je unikatne.\n\n");
  vwrite_user(user,"   ~OL%s\n\n",buff);
  return NULL;
  }
else return(last);
}


/*** Get room struct pointer from abbreviated name ***/
RM_OBJECT get_room(char *name)
{
	RM_OBJECT rm;

	for (rm=room_first;rm!=NULL;rm=rm->next)
		if (!strncmp(rm->name,name,strlen(name))) return rm;
	return NULL;
}


/*** Get room struct pointer from full name ***/
RM_OBJECT get_room_full(char *name)
{
	RM_OBJECT rm;

	set_crash();
	for (rm=room_first; rm!=NULL; rm=rm->next)
		if (!strcmp(rm->name, name)) return rm;
	return NULL;
}



/*** See if a user has access to a room. If room is fixed to private then
	it is considered a wizroom so grant permission to any user of WIZ and
	above for those. ***/
int has_room_access(UR_OBJECT user, RM_OBJECT rm)
{
	int i=0;

	set_crash();
/* root check */
if (rm->access==ROOT_CONSOLE) {
	if (user->level==ROOT || user->invite_room==rm) return 1;
	else return 0;
	}
/* level room checks */
while (priv_room[i].name[0]!='*') {
  if (!strcmp(rm->name,priv_room[i].name)
      && user->level<priv_room[i].level
      && user->invite_room!=rm) return 0;
  i++;
  }
/* personal room checks */
if (rm->access==PERSONAL_UNLOCKED) return 1; /* open to all */
if ((rm->access==PERSONAL_LOCKED && is_my_room(user,rm))
    || has_room_key(user->name,rm)
    || user->level>=GOD
    || user->invite_room==rm) return 1;
if ((rm->access==PERSONAL_LOCKED && !is_my_room(user,rm))
    && user->level<GOD
    && user->invite_room!=rm) return 0;
/* fixed room checks */
if ((rm->access & PRIVATE) 
    && user->level<amsys->gatecrash_level 
    && user->invite_room!=rm
    && !((rm->access & FIXED) && user->level>=WIZ)) return 0;
/* have access */
return 1;
}


/* Check the room you're logging into isn't private */
void check_start_room(UR_OBJECT user)
{
	RM_OBJECT rm;

	set_crash();
	if (!user->logout_room[0] || !user->lroom) {
		user->room=room_first;
		return;
		}
	rm=get_room(user->logout_room);
	if (rm==NULL) {
		user->room=room_first;
		return;
		}
	if (rm->access==PRIVATE || (rm->access==FIXED_PRIVATE && user->level<WIZ) || (rm->access==ROOT_CONSOLE && user->level<ROOT)) {
		vwrite_user(user,"\nRuuma v ktorej si sa odlogoval%s je teraz ~FRPRIVAT~RS - pripajam ta do %s.\n\n", grm_gnd(4, user->gender), room_first->name);
		user->room=room_first;
		return;
		}
	user->room=rm;
	if (user->lroom==2)
		vwrite_user(user,"\nBol%s si ~FRprilepen%s~RS do ruumy ~FG%s~RS\n\n",
			grm_gnd(4, user->gender), grm_gnd(1, user->gender), rm->name);
	else
		vwrite_user(user,"\nYou are connecting into the ~FG%s~RS room.\n\n",
			rm->name);
}


/*** find out if a user is listed in the user linked list ***/
int find_user_listed(char *name)
{
	struct user_dir_struct *entry;

	name[0]=toupper(name[0]);
	for (entry=first_dir_entry;entry!=NULL;entry=entry->next)
		if (!strcmp(entry->name,name)) return 1;
	return 0;
}


/*** Checks to see if a user with the given name is currently logged on ***/
int user_logged_on(char *name)
{
	UR_OBJECT u;

	for (u=user_first;u!=NULL;u=u->next) {
		if (u->login) continue;
		if (!strcmp(name,u->name)) return 1;
		}
	return 0;
}


/*** Checks to see if the room a user is in is private ***/
int in_private_room(UR_OBJECT user)
{
	if (user->room->access==PRIVATE || user->room->access==FIXED_PRIVATE || user->room->access==ROOT_CONSOLE)  return 1;
	return 0;
}


/*** Check to see if a command has been given to a user ***/
int has_gcom(UR_OBJECT user, int cmd_id)
{
	int i;

	for (i=0;i<MAX_GCOMS;i++)
		if (user->gcoms[i]==cmd_id) return 1;
	return 0;
}


/*** Check to see if a command has been taken from a user ***/
int has_xcom(UR_OBJECT user, int cmd_id)
{
	int i;

	for (i=0;i<MAX_XCOMS;i++)
		if (user->xcoms[i]==cmd_id) return 1;
	return 0;
}


/**** check to see if the room given is a personal room ***/
int is_personal_room(RM_OBJECT rm)
{
	if (rm->access==PERSONAL_LOCKED || rm->access==PERSONAL_UNLOCKED) return 1;
	return 0;
}


/**** find out if the room given is the perosnal room of the user ***/
int is_my_room(UR_OBJECT user,RM_OBJECT rm)
{
	char name[ROOM_NAME_LEN+1];

	set_crash();
	sprintf(name,"(%s)",user->name);
	strtolower(name);
	if (!strcmp(name,rm->name)) return 1;
	return 0;
}


/*** check to see how many people are in a given room ***/
int room_visitor_count(RM_OBJECT rm)
{
	UR_OBJECT u;
	int cnt=0;

	if (rm==NULL) return cnt;
	for (u=user_first;u!=NULL;u=u->next)
		if (u->room==rm) ++cnt;
	return cnt;
}


/*** See if user is banned ***/
int has_room_key(char *visitor,RM_OBJECT rm)
{
	FILE *fp;
	char line[82],fname[FNAME_LEN],rmname[USER_NAME_LEN];

	set_crash();
	/* get user's name from room name */
	midcpy(rm->name,rmname,1,strlen(rm->name)-2);
	rmname[0]=toupper(rmname[0]);
	/* check if user is listed */
	sprintf(fname,"%s/%s.K", USERROOMS, rmname);
	if (!(fp=fopen(fname,"r"))) return 0;
	fscanf(fp,"%s",line);
	while (!feof(fp)) {
		if (!strcmp(line,visitor)) {
			fclose(fp);
			return 1;
			}
		fscanf(fp,"%s",line);
		}
	fclose(fp);
	return 0;
}



/******************************************************************************
 Setting up of the sockets
 *****************************************************************************/

/*** Set up readmask for select ***/
void setup_readmask(fd_set *mask)
{
	UR_OBJECT user;
#ifdef NETLINKS
	NL_OBJECT nl;
#endif
	int i;
  
	FD_ZERO(mask);
	for (i=0;i<port_total;++i)
		FD_SET(listen_sock[i],mask);
/* Do users */
	for (user=user_first;user!=NULL;user=user->next) 
		if (user->type==USER_TYPE) FD_SET(user->socket,mask);
/* Do client-server stuff */
#ifdef NETLINKS
	for(nl=nl_first;nl!=NULL;nl=nl->next) 
		if (nl->type!=UNCONNECTED) FD_SET(nl->socket,mask);
#endif
}


/*** Accept incoming connections on listen sockets ***/
void accept_connection(int lsock, int num)
{
	UR_OBJECT user;
	char named_site[80], ip_site[16], motdname[FNAME_LEN];
	struct sockaddr_in acc_addr;
	int accept_sock;
	unsigned int size;

	named_site[0]=ip_site[0]='\0';
	size=sizeof(struct sockaddr_in);
	accept_sock=accept(lsock,(struct sockaddr *)&acc_addr,&size);
#ifdef NETLINKS
	if (num==2) {
		accept_server_connection(accept_sock,acc_addr);
		return;
		}
#endif
/* Get addr */
	get_net_addresses(acc_addr, ip_site, named_site);

	if (site_banned(ip_site,0) || site_banned(named_site,0)) {
		write_sock(accept_sock,"\n\rLoginy z tvojej sajty/domeny su zabanovane.\n\n\r");
		close(accept_sock);
		write_syslog(SYSLOG, 1, "Pokus o login zo zabanovanej sajty %s (%s).\n",named_site,ip_site);
		return;
		}
	if (amsys->flood_protect && (login_port_flood(ip_site) || login_port_flood(named_site))) {
		write_sock(accept_sock, flood_prompt_r);
		close(accept_sock);
		write_syslog(SYSLOG, 1, "Pokus o vyfloodovanie portu zo sajty %s (%s).\n",named_site,ip_site);
		auto_ban_site(ip_site);
		return;
		}
/* get random motd1 and send pre-login message */
	if (amsys->motd1_cnt) {
		sprintf(motdname,"%s/motd1/motd%d", MOTDFILES, (get_motd_num(1)));
		more(NULL, accept_sock, motdname);
		}
	else {
		sprintf(text,"Wytay na %s!\n\n\rSorry, zda sa, ze logovacia obrazovka sa stratila\n\r",reg_sysinfo[TALKERNAME]);
		write_sock(accept_sock,text);
		}
	if (syspp->acounter[3]+amsys->num_of_logins>=amsys->max_users && !num) {
		write_sock(accept_sock,"\n\rSorac, ale momentalne nemozeme akceptovat viac pripojeni.  Skus neskor.\n\n\r");
		close(accept_sock);  
		return;
		}
	if (!num && !syspp->sys_access) {
		write_sock(accept_sock, sys_port_closed);
		close(accept_sock);
		return;
		}
	if (num && !syspp->wiz_access) {
		write_sock(accept_sock, wiz_port_closed);
		close(accept_sock);
		return;
		}
	if ((user=create_user())==NULL) {
		sprintf(text,"\n\r%s: nemozem vytvorit session.\n\n\r",syserror);
		write_sock(accept_sock,text);
		close(accept_sock);  
		return;
		}
	user->socket=accept_sock;
	user->auth_addr=acc_addr.sin_addr.s_addr;
	user->login=LOGIN_NAME;
	user->last_input=time(0);
	if (!num) user->port=port[0]; 
	else {
		user->port=port[1];
		write_user(user,"~FT~OL** Wizport login **~RS\n\n");
		}
#ifdef PUEBLO
	if (syspp->pueblo_enh)
		vwrite_user(user, "~RS~OLLotos verzia %s - Tento system je \'~FRPueblo 1.10 Enhanced~RS~OL\'.\n\n", OSSVERSION);
#endif
	strcpy(user->site,named_site);
	strcpy(user->ipsite,ip_site);
	user->site_port=(int)ntohs(acc_addr.sin_port);
	echo_on(user);
	write_user(user, login_prompt);
	amsys->num_of_logins++;
}


/*** Resolve an IP address if the resolve_ip set to MANUAL in config file.
     This code was written by tref, and submitted to ewtoo.org by ruGG.
     Claimed useful for BSD systems in which gethostbyaddr() calls caused
     extreme hanging/blocking of the talker.  Note, popen is a blocking 
     call however.
     ***/
char *resolve_ip(char* host)
{
	FILE* hp;
	static char str[256];
	char *txt,*t;

	sprintf(str,"/usr/bin/host %s",host);
	hp=popen(str,"r");

	*str=0;
	fgets(str,255,hp);
	pclose(hp);

	txt=strchr(str,':');
	if (txt) {
		txt++;
		while (isspace(*txt))
			txt++; 
		t=txt;
		while (*t && *t!='\n')
			t++;
		*t=0;
		return(txt);
		}
	return(host);
}



/******************************************************************************
 Signal handlers and exit functions
 *****************************************************************************/

/*** Talker signal handler function. Can either shutdown, ignore or reboot
	if a unix error occurs though if we ignore it we're living on borrowed
	time as usually it will crash completely after a while anyway. ***/
void sig_handler(int sig)
{
	set_crash();
#ifdef DEBUG
	crash_dump();
#endif
	force_listen=1;
	dump_commands(sig);
	switch (sig) {
		case SIGHUP:
			restart(NULL);
			return;
  case SIGTERM:
    if (amsys->ignore_sigterm) {
      write_syslog(SYSLOG,1,"SIGTERM signal prijaty - ignorujem.\n");
      return;
      }
    write_room(NULL,"\n\n~OLSYSTEM:~FR~LI SIGTERM prijaty, inicializujem vypnutie !\n\n");
    talker_shutdown(NULL,"ukoncovaci signal (SIGTERM)",0); 
    break; /* don't really need this here, but better safe... */

  case SIGSEGV:
    switch (amsys->crash_action) {
      case 0:	
	write_room(NULL,"\n\n\07~OLSYSTEM:~FR~LI SAKRA - Chyba segmentacie, inicializujem vypnutie!\n\n");
#ifdef DEBUG
	crash_dump();
#endif
	talker_shutdown(NULL,"chyba segmentacie (SIGSEGV)",0); 
	break;

      case 1:	
	write_room(NULL,"\n\n\07~OLSYSTEM:~FR~LI POZOR - Vyskytla sa chyba segmentacie !\n\n");
	write_syslog(SYSLOG,1,"POZOR: Vyskytla sa chyba segmentacie !\n");
#ifdef DEBUG
	crash_dump();
#endif
	longjmp(jmpvar,0);
	break;

      case 2:
	write_room(NULL,"\n\n\07~OLSYSTEM:~FR~LI SAKRA - Chyba segmentacie, inicializujem reboot!\n\n");
#ifdef DEBUG
	crash_dump();
#endif
	talker_shutdown(NULL,"Chyba segmentacie (SIGSEGV)",1); 
	break;
	
      case 3: //restart
	write_room(NULL,"\n\n\07~OLSYSTEM:~FR~LI POZOR - Vyskytla sa chyba segmentacie !\n\n");
	write_syslog(SYSLOG,1,"POZOR: Vyskytla sa chyba segmentacie !\n");
#ifdef DEBUG
	crash_dump();
#endif
	restart(NULL);
	break;

      case 4: //shutdown
	write_room(NULL,"\n\n\07~OLSYSTEM:~FR~LI POZOR - Vyskytla sa chyba segmentacie !\n\n");
	write_syslog(SYSLOG,1,"POZOR: Vyskytla sa chyba segmentacie !\n");
#ifdef DEBUG
	crash_dump();
#endif
	talker_shutdown(NULL, "SIGSEG", 0);
	break;
    } /* end switch */

  case SIGBUS:
    switch(amsys->crash_action) {
      case 0:
	write_room(NULL,"\n\n\07~OLSYSTEM:~FR~LI SAKRA - Bus error, inicializujem vypnutie!\n\n");
#ifdef DEBUG
	crash_dump();
#endif
	talker_shutdown(NULL,"a bus error (SIGBUS)",0);
	break;

      case 1:
	write_room(NULL,"\n\n\07~OLSYSTEM:~FR~LI POZOR - A bus error has just occured!\n\n");
	write_syslog(SYSLOG,1,"POZOR: A bus error occured!\n");
#ifdef DEBUG
	crash_dump();
#endif
	longjmp(jmpvar,0);
	break;

      case 2:
	write_room(NULL,"\n\n\07~OLSYSTEM:~FR~LI SAKRA - Bus error, inicializujem reboot!\n\n");
#ifdef DEBUG
	crash_dump();
#endif
	talker_shutdown(NULL,"a bus error (SIGBUS)",1);
	break;
    } /* end switch */
  } /* end switch */
}


/*** Exit because of error during bootup ***/
void boot_exit(int code)
{
	set_crash();
switch (code) {
  case 1:
    write_syslog(SYSLOG,1,"BOOT FAILURE: Chyba pri rozbore config fajlu.\n");
    exit(1);

  case 2:
    perror("Lotos: Can't open main port listen socket");
    write_syslog(SYSLOG,1,"BOOT FAILURE: Can't open main port listen socket.\n");
    exit(2);

  case 3:
    perror("Lotos: Can't open wiz port listen socket");
    write_syslog(SYSLOG,1,"BOOT FAILURE: Can't open wiz port listen socket.\n");
    exit(3);

  case 4:
    perror("Lotos: Can't open link port listen socket");
    write_syslog(SYSLOG,1,"BOOT FAILURE: Can't open link port listen socket.\n");
    exit(4);

  case 5:
    perror("Lotos: nemozem prepojit na main port");
    write_syslog(SYSLOG,1,"BOOT FAILURE: nemozem prepojit na main port.\n");
    exit(5);

  case 6:
    perror("Lotos: nemozem prepojit na wiz port");
    write_syslog(SYSLOG,1,"BOOT FAILURE: nemozem prepojit na wiz port.\n");
    exit(6);

  case 7:
    perror("Lotos: nemozem prepojit na link port");
    write_syslog(SYSLOG,1,"BOOT FAILURE: nemozem prepojit na link port.\n");
    exit(7);

  case 8:
    perror("Lotos: Listen error on main port");
    write_syslog(SYSLOG,1,"BOOT FAILURE: Listen error on main port.\n");
    exit(8);

  case 9:
    perror("Lotos: Listen error on wiz port");
    write_syslog(SYSLOG,1,"BOOT FAILURE: Listen error on wiz port.\n");
    exit(9);

  case 10:
    perror("Lotos: Listen error on link port");
    write_syslog(SYSLOG,1,"BOOT FAILURE: Listen error on link port.\n");
    exit(10);

  case 11:
    perror("Lotos: Failed to fork");
    write_syslog(SYSLOG,1,"BOOT FAILURE: Failed to fork.\n");
    exit(11);

  case 12:
    perror("Lotos: Failed to parse user structure");
    write_syslog(SYSLOG,1,"BOOT FAILURE: Failed to parse user structure.\n");
    exit(12);

  case 13:
    perror("Lotos: Failed to parse user commands");
    write_syslog(SYSLOG,1,"BOOT FAILURE: Failed to parse user commands.\n");
    exit(13);

  case 14:
    write_syslog(SYSLOG,1,"BOOT FAILURE: mena levelov nie su unikatne.\n");
    exit(14);

  case 15:
    write_syslog(SYSLOG,1,"BOOT FAILURE: chyba citania struktury adresarov USERFILES.\n");
    exit(15);

  case 16:
    perror("Lotos: struktura adresarov v USERFILES je nekorektna");
    write_syslog(SYSLOG,1,"BOOT FAILURE: struktura adresarov v USERFILES je nekorektna.\n");
    exit(16);

  case 17:
    perror("Lotos: nemozem vytvorit docasnu user strukturu");
    write_syslog(SYSLOG,1,"BOOT FAILURE: nemozem vytvorit docasnu user strukturu.\n");
    exit(17);

  case 18:
    perror("Lotos: Failed to parse a user structure");
    write_syslog(SYSLOG,1,"BOOT FAILURE: Failed to parse a user structure.\n");
    exit(18);

  case 19:
    perror("Lotos: nemozem otvorit adresar USERROOMS pre citanie");
    write_syslog(SYSLOG,1,"BOOT FAILURE: nemozem otvorit adresar USERROOMS.\n");
    exit(19);

  case 20:
    perror("Lotos: nemozem otvorit adresar v MOTDFILES pre citanie");
    write_syslog(SYSLOG,1,"BOOT FAILURE: nemozem otvorit adresar MOTDFILES.\n");
    exit(20);

  case 21:
    perror("Lotos: nemozem vytvorit system object");
    write_syslog(SYSLOG,1,"BOOT FAILURE: nemozem vytvorit system object.\n");
    exit(21);

  case 101:
    perror("Lotos: nemozem otvorit adresar TEXTFILES pre citanie");
    write_syslog(SYSLOG, 1, "BOOT FAILURE: nemozem otvorit adresar TEXTFILES.\n");
    exit(101);

  case 102:
    perror("Lotos: nemozem vytvorit tempfajl v TMPFILES");
    write_syslog(SYSLOG, 1, "BOOT FAILURE: nemozem vytvorit tempfajl v TMPFILES.\n");
    exit(102);

  case 103:
    perror("Lotos: nemozem otvorit subor na citanie v TXTFILES");
    write_syslog(SYSLOG, 1, "BOOT FAILURE: nemozem otvorit subor na citanie v TXTFILES.\n");
    exit(103);

  case 121:
    perror("Lotos: nemozem vytvorit syspp object");
    write_syslog(SYSLOG,1,"BOOT FAILURE: nemozem vytvorit syspp object.\n");
    exit(121);
  } /* end switch */
}


/*** Records when the user last logged on for use with the .last command ***/
void record_last_login(char *name)
{
	int i;

	set_crash();
	for (i=LASTLOGON_NUM; i>0; i--) {
		strcpy(last_login_info[i].name,last_login_info[i-1].name);
		strcpy(last_login_info[i].time,last_login_info[i-1].time);
		last_login_info[i].on=last_login_info[i-1].on;
		}    
	strcpy(last_login_info[0].name,name);
	strcpy(last_login_info[0].time,long_date(1));
	last_login_info[0].on=1;
}


/*** Records when the user last logged out for use with the .last command ***/
void record_last_logout(char *name)
{
	int i=0;

	set_crash();
	while (i<LASTLOGON_NUM) {
		if (!strcmp(last_login_info[i].name,name)) break;
		i++;
		}
	if (i!=LASTLOGON_NUM) last_login_info[i].on=0;
}



/******************************************************************************
 Initializing of globals and other stuff
 *****************************************************************************/
/*** Load the users details ***/
int load_user_details(UR_OBJECT user)
{
	FILE *fp;
	char user_words[16][40]; /* must be at least 1 longer than max words in the _options */
	char line[ARR_SIZE], fname[FNAME_LEN], *str;
	char *ver;
	int  wn, wpos, wcnt, op, found, i, damaged=0;
	char *userfile_options[]={
		"version","password","promote_date","times","levels","general","user_set",
		"fighting","purging","last_site","mail_verify","description",
		"in_phrase","out_phrase","email","homepage","recap_name",
		"prompt", "nick_grm", "pueblo", "restrict", "ign_word", "*" /* KEEP HERE! */
		};

	set_crash();
	sprintf(fname,"%s/%s.D", USERFILES, user->name);
	if (!(fp=fopen(fname,"r"))) return 0;

fgets(line,ARR_SIZE-1,fp);
line[strlen(line)-1]='\0';

if (strcmp(USERVER, ver=remove_first(line))) {
	fclose(fp);
	i=load_user_olddetails(user, ver);
	return i;
	}

while (!feof(fp)) {
  /* make this into the functions own word array.  This allows this array to
     have a different length from the general words array. */
  wn=0;
  wpos=0;
  str=line;
  do {
    while (*str<33) if (!*str++) goto LUOUT;
    while (*str>32 && wpos<40) user_words[wn][wpos++]=*str++;
    user_words[wn++][wpos]='\0';
    wpos=0;
  } while (wn<16);
  wn--;
 LUOUT:
  wcnt=wn;
  /* now get the option we're on */
  op=0;
  found=1;
  while (strcmp(userfile_options[op],user_words[0])) {
    if (userfile_options[op][0]=='*') { found=0; break; }
    op++;
    }
  if (found) {
    switch (op) {
      case 0:
	if (wcnt>=2) {      /* make sure more than just option string was there */
	  strcpy(user->version,remove_first(line));
	  }
	break;
      case 1:
	if (wcnt>=2) strcpy(user->pass,remove_first(line));
	break;
      case 2:
	if (wcnt>=2) strcpy(user->date,remove_first(line));
	break;
      case 3:
	for (i=1;i<wcnt;i++)
	  switch(i) {
	    case 1: user->last_login=(time_t)atoi(user_words[i]);  break;
	    case 2: user->total_login=(time_t)atoi(user_words[i]);  break;
	    case 3: user->last_login_len=atoi(user_words[i]);  break;
	    case 4: user->read_mail=(time_t)atoi(user_words[i]);  break;
	    }
	break;
      case 4:
	for (i=1;i<wcnt;i++)
	  switch(i) {
	    case 1: user->level=atoi(user_words[i]);  break;
	    case 2: user->unarrest=atoi(user_words[i]);  break;
	    case 3: user->arrestby=atoi(user_words[i]);  break;
	    case 4: user->muzzled=atoi(user_words[i]);  break;
	    }
	break;
      case 5:
	for (i=1;i<wcnt;i++)
	  switch(i) {
	    case 1: user->accreq=atoi(user_words[i]);  break;
	    case 2: user->command_mode=atoi(user_words[i]);  break;
	    case 3: user->prompt=atoi(user_words[i]);  break;
	    case 4: user->vis=atoi(user_words[i]);  break;
	    case 5: user->monitor=atoi(user_words[i]);  break;
	    case 6: user->mail_verified=atoi(user_words[i]);  break;
	    case 7: user->logons=atoi(user_words[i]);  break;
		case 8: user->terminal.xterm=atoi(user_words[i]);  break;
	    }
	break;
      case 6:
	for (i=1;i<wcnt;i++)
	  switch(i) {
	    case  1: user->gender=atoi(user_words[i]);  break;
	    case  2: user->age=atoi(user_words[i]);  break;
	    case  3: user->hideemail=atoi(user_words[i]);  break;
	    case  4: user->lroom=atoi(user_words[i]);  break;
	    case  5: user->alert=atoi(user_words[i]);  break;
	    case  6: user->autofwd=atoi(user_words[i]);  break;
	    case  7: user->show_pass=atoi(user_words[i]);  break;
	    case  8: user->show_rdesc=atoi(user_words[i]);  break;
	    case  9: user->cmd_type=atoi(user_words[i]);  break;
	    case 10: strcpy(user->icq, user_words[i]);  break;
	    case 11: user->who_type=atoi(user_words[i]); break;
	    }
	break;
      case 7:
	for (i=1;i<wcnt;i++)
	  switch(i) {
	    case 1: user->hits=atoi(user_words[i]);  break;
	    case 2: user->misses=atoi(user_words[i]);  break;
	    case 3: user->deaths=atoi(user_words[i]);  break;
	    case 4: user->kills=atoi(user_words[i]);  break;
	    case 5: user->bullets=atoi(user_words[i]);  break;
	    case 6: user->hps=atoi(user_words[i]);  break;
		case 7: user->money=atoi(user_words[i]); break;
		case 8: user->bank=atoi(user_words[i]); break;
	    }
	break;
      case 8:
	for (i=1;i<wcnt;i++)
	  switch(i) {
	    case 1: user->expire=atoi(user_words[i]);  break;
	    case 2: user->t_expire=(time_t)atoi(user_words[i]);  break;
	    }
	break;
      case  9:
	for (i=1;i<wcnt;i++)
	  switch(i) {
	    case 1: strcpy(user->last_site,user_words[i]);  break;
	    case 2: strcpy(user->logout_room,user_words[i]);  break;
	    }
	break;
      case 10:
	if (wcnt>=2) strcpy(user->verify_code,remove_first(line));
	break;
      case 11:
	if (wcnt>=2) strcpy(user->desc,remove_first(line));
	break;
      case 12:
	if (wcnt>=2) strcpy(user->in_phrase,remove_first(line));
	break;
      case 13:
	if (wcnt>=2) strcpy(user->out_phrase,remove_first(line));
	break;
      case 14:
	if (wcnt>=2) strcpy(user->email,remove_first(line));
	break;
      case 15:
	if (wcnt>=2) strcpy(user->homepage,remove_first(line));
	break;
      case 16:
	if (wcnt>=2) strcpy(user->recap,remove_first(line));
	break;
      case 17:
        for (i=1; i<wcnt; i++)
          switch(i) {
            case 1: strcpy(user->prompt_str, user_words[i]); break;
            }
        break;
      case 18:
        for (i=1; i<wcnt; i++)
          switch(i) {
            case 1: strcpy(user->nameg, user_words[i]); break;
            case 2: strcpy(user->named, user_words[i]); break;
            case 3: strcpy(user->namea, user_words[i]); break;
            case 4: strcpy(user->namel, user_words[i]); break;
            case 5: strcpy(user->namei, user_words[i]); break;
            case 6: strcpy(user->namex, user_words[i]); break;
            case 7: strcpy(user->namey, user_words[i]); break;
            case 8: strcpy(user->namez, user_words[i]); break;
            }
        break;
      case 19:
#ifdef PUEBLO
        for (i=1; i<wcnt; i++)
          switch (i) {
            case 1: user->pueblo_mm=atoi(user_words[i]); break;
            case 2: user->pueblo_pg=atoi(user_words[i]); break;
            case 3: user->voiceprompt=atoi(user_words[i]); break;
            }
#endif
        break;
      case 20:
        if (wcnt>=2) strcpy(user->restrict, remove_first(line));
        else strcpy(user->restrict, RESTRICT_MASK);
        break;
      case 21:
        if (wcnt>=2) user->ign_word=strdup(remove_first(line));
	break;
      default: damaged++; break;
      }
    }
  else damaged++;
  fgets(line,ARR_SIZE-1,fp);
  line[strlen(line)-1]=0;
  }
fclose(fp);
/* binarne ukladane data */
	sprintf(fname, "%s/bin/%s.D", USERFILES, user->name);
	if (!(fp=fopen(fname, "rb"))) return 0;
	fread(&user->ignore, sizeof(USER_IGNORE), 1, fp);
	fread(&user->terminal, sizeof(USER_TERMINAL), 1, fp);
	fclose(fp);

if (damaged) write_syslog(SYSLOG,1,"Poskodeny userfajl '%s.D'\n",user->name);
if (!user->recap[0]) strcpy(user->recap,user->name);
strcpy(user->bw_recap,colour_com_strip(user->recap));
user->real_level=user->level;
if (user->level==ROOT && strcmp(user->name, reg_sysinfo[SYSOPUNAME])) {
	user->real_level=NEW;
	write_syslog(SYSLOG, 1, "~CRAutodemote~RS %s from %s to %s - edited userfile\n",
		user->name, user_level[user->level].name, user_level[user->real_level].name);
	sprintf(text, "~CRAutodemote~RS from %s to %s - edited userfile\n",
		user_level[user->level].name, user_level[user->real_level].name);
	add_history(user->name, 1, text);
	user->vis=1;
	add_user_date_node(user->name, long_date(1));
	user->unarrest=NEW;
	user->arrestby=ROOT;
	user->level=JAILED;
	user_list_level(user->name, user->level);
	strcpy(user->date, long_date(1));
	strcpy(user->site, user->last_site);
	save_user_details(user, 0);
	}
if (user->level>NEW) user->accreq=-1;   /* compensate for new accreq change */
get_macros(user);
get_xgcoms(user);
get_friends(user);
read_user_reminders(user);
return 1;
}

int load_user_olddetails(UR_OBJECT user, char *ver)
{
	if (!strcmp(ver, "0.10")) return(load_user_olddetails010(user));
	if (!strcmp(ver, "0.11")) return(load_user_olddetails011(user));
	return 0;
}

/*** Load the old users details v0.10 ***/
int load_user_olddetails010(UR_OBJECT user)
{
	FILE *fp;
	char user_words[15][20]; /* must be at least 1 longer than max words in the _options */
	char line[ARR_SIZE],fname[FNAME_LEN],*str;
	int  wn,wpos,wcnt,op,found,i,damaged,version_found;
	char *userfile_options[]={
		"version","password","promote_date","times","levels","general","user_set",
		"user_ignores","fighting","purging","last_site","mail_verify","description",
		"in_phrase","out_phrase","email","homepage","recap_name",
		"prompt", "nick_grm", "pueblo", "restrict", "ign_word", "*" /* KEEP HERE! */
		};

	set_crash();
	write_syslog(SYSLOG, 1, "Nahravam staru verziu userfajlu pre %s, v0.1 > 1.0.0-1.1.1\n", user->name);

sprintf(fname,"%s/%s.D", USERFILES, user->name);
if (!(fp=fopen(fname,"r"))) return 0;

damaged=version_found=0;
fgets(line,ARR_SIZE-1,fp);
line[strlen(line)-1]='\0';

while (!feof(fp)) {
  /* make this into the functions own word array.  This allows this array to
     have a different length from the general words array. */
  wn=0; wpos=0;
  str=line;
  do {
    while (*str<33) if (!*str++) goto LUOUT;
    while (*str>32 && wpos<20) user_words[wn][wpos++]=*str++;
    user_words[wn++][wpos]='\0';
    wpos=0;
  } while (wn<15);
  wn--;
 LUOUT:
  wcnt=wn;
  /* now get the option we're on */
  op=0;  found=1;
  while (strcmp(userfile_options[op],user_words[0])) {
    if (userfile_options[op][0]=='*') { found=0; break; }
    op++;
    }
  if (found) {
    switch(op) {
      case 0:
	if (wcnt>=2) {      /* make sure more than just option string was there */
	  strcpy(user->version,remove_first(line));
	  version_found=1;  /* gotta compensate still for old versions */
	  }
	break;
      case 1:
	if (wcnt>=2) strcpy(user->pass,remove_first(line));
	break;
      case 2:
	if (wcnt>=2) strcpy(user->date,remove_first(line));
	break;
      case 3:
	for (i=1;i<wcnt;i++)
	  switch(i) {
	    case 1: user->last_login=(time_t)atoi(user_words[i]);  break;
	    case 2: user->total_login=(time_t)atoi(user_words[i]);  break;
	    case 3: user->last_login_len=atoi(user_words[i]);  break;
	    case 4: user->read_mail=(time_t)atoi(user_words[i]);  break;
	    }
	break;
      case 4:
	for (i=1;i<wcnt;i++)
	  switch(i) {
	    case 1: user->level=atoi(user_words[i]);  break;
	    case 2: user->unarrest=atoi(user_words[i]);  break;
	    case 3: user->arrestby=atoi(user_words[i]);  break;
	    case 4: user->muzzled=atoi(user_words[i]);  break;
	    }
	break;
      case 5:
	for (i=1;i<wcnt;i++)
	  switch(i) {
	    case 1: user->accreq=atoi(user_words[i]);  break;
	    case 2: user->terminal.checho=atoi(user_words[i]); break;
	    case 3: user->command_mode=atoi(user_words[i]);  break;
	    case 4: user->prompt=atoi(user_words[i]); break;
	    case 5: user->vis=atoi(user_words[i]);  break;
	    case 6: user->monitor=atoi(user_words[i]);  break;
	    case 7: user->mail_verified=atoi(user_words[i]);  break;
	    case 8: user->logons=atoi(user_words[i]);  break;
		case 9: user->terminal.xterm=atoi(user_words[i]);  break;
	    }
	break;
      case 6:
	for (i=1;i<wcnt;i++)
	  switch(i) {
	    case 1 : user->gender=atoi(user_words[i]);  break;
	    case 2 : user->age=atoi(user_words[i]);  break;
	    case 3 : user->terminal.wrap=atoi(user_words[i]);  break;
	    case 4 : user->terminal.pager=atoi(user_words[i]);  break;
	    case 5 : user->hideemail=atoi(user_words[i]);  break;
	    case 6 : user->terminal.txt=user->terminal.bckg=atoi(user_words[i]); break;
	    case 7 : user->lroom=atoi(user_words[i]);  break;
	    case 8 : user->alert=atoi(user_words[i]);  break;
	    case 9 : user->autofwd=atoi(user_words[i]);  break;
	    case 10: user->show_pass=atoi(user_words[i]);  break;
	    case 11: user->show_rdesc=atoi(user_words[i]);  break;
	    case 12:
	    	user->cmd_type=atoi(user_words[i]);
		if (user->cmd_type==0) user->cmd_type=1;
		break;
	    case 13: strcpy(user->icq, user_words[i]);  break;
	    }
	break;
      case 7:
	for (i=1;i<wcnt;i++)
	  switch(i) {
	    case  1: user->ignore.all=atoi(user_words[i]);  break;
	    case  2: user->ignore.tells=atoi(user_words[i]);  break;
	    case  3: user->ignore.shouts=atoi(user_words[i]);  break;
	    case  4: user->ignore.pics=atoi(user_words[i]);  break;
	    case  5: user->ignore.logons=atoi(user_words[i]);  break;
	    case  6: user->ignore.wiz=atoi(user_words[i]);  break;
	    case  7: user->ignore.greets=atoi(user_words[i]);  break;
	    case  8: user->ignore.beeps=atoi(user_words[i]);  break;
	    case  9: user->ignore.transp=atoi(user_words[i]); break;
	    case 10: user->ignore.funs=atoi(user_words[i]); break;
	    }
	break;
      case 8:
	for (i=1;i<wcnt;i++)
	  switch(i) {
	    case 1: user->hits=atoi(user_words[i]);  break;
	    case 2: user->misses=atoi(user_words[i]);  break;
	    case 3: user->deaths=atoi(user_words[i]);  break;
	    case 4: user->kills=atoi(user_words[i]);  break;
	    case 5: user->bullets=atoi(user_words[i]);  break;
	    case 6: user->hps=atoi(user_words[i]);  break;
	    }
	break;
      case 9:
	for (i=1;i<wcnt;i++)
	  switch(i) {
	    case 1: user->expire=atoi(user_words[i]);  break;
	    case 2: user->t_expire=(time_t)atoi(user_words[i]);  break;
	    }
	break;
      case 10:
	for (i=1;i<wcnt;i++)
	  switch(i) {
	    case 1: strcpy(user->last_site,user_words[i]);  break;
	    case 2: strcpy(user->logout_room,user_words[i]);  break;
	    }
	break;
      case 11:
	if (wcnt>=2) strcpy(user->verify_code,remove_first(line));
	break;
      case 12:
	if (wcnt>=2) strcpy(user->desc,remove_first(line));
	break;
      case 13:
	if (wcnt>=2) strcpy(user->in_phrase,remove_first(line));
	break;
      case 14:
	if (wcnt>=2) strcpy(user->out_phrase,remove_first(line));
	break;
      case 15:
	if (wcnt>=2) strcpy(user->email,remove_first(line));
	break;
      case 16:
	if (wcnt>=2) strcpy(user->homepage,remove_first(line));
	break;
      case 17:
	if (wcnt>=2) strcpy(user->recap,remove_first(line));
	break;
      case 18:
        for (i=1; i<wcnt; i++)
          switch(i) {
            case 1: user->prompt=atoi(user_words[i]); break;
            case 2: strcpy(user->prompt_str, user_words[i]); break;
            }
        break;
      case 19:
        for (i=1; i<wcnt; i++)
          switch(i) {
            case 1: strcpy(user->nameg, user_words[i]); break;
            case 2: strcpy(user->named, user_words[i]); break;
            case 3: strcpy(user->namea, user_words[i]); break;
            case 4: strcpy(user->namel, user_words[i]); break;
            case 5: strcpy(user->namei, user_words[i]); break;
            }
        break;
      case 20:
#ifdef PUEBLO
        for (i=1; i<wcnt; i++)
          switch (i) {
            case 1: user->pueblo_mm=atoi(user_words[i]); break;
            case 2: user->pueblo_pg=atoi(user_words[i]); break;
            case 3: user->voiceprompt=atoi(user_words[i]); break;
            }
#endif
        break;
      case 21:
        if (wcnt>=2) strcpy(user->restrict, remove_first(line));
        else strcpy(user->restrict, RESTRICT_MASK);
        break;
      case 22:
        if (wcnt>=2) user->ign_word=strdup(remove_first(line));
	break;
      default: damaged++; break;
      }
    }
  else damaged++;
  fgets(line,ARR_SIZE-1,fp);
  line[strlen(line)-1]=0;
  }
fclose(fp);
if (damaged) write_syslog(SYSLOG,1,"Poskodeny userfajl '%s.D'\n",user->name);
strcpy(user->recap,user->name);
strcpy(user->bw_recap,colour_com_strip(user->recap));
user->real_level=user->level;
if (user->level>NEW) user->accreq=-1;   /* compensate for new accreq change */
get_macros(user);
get_xgcoms(user);
get_friends(user);
read_user_reminders(user);
return 1;
}

/*** Load the old users details v0.11 ***/
int load_user_olddetails011(UR_OBJECT user)
{
	FILE *fp;
	char user_words[16][40]; /* must be at least 1 longer than max words in the _options */
	char line[ARR_SIZE],fname[FNAME_LEN],*str;
	int  wn,wpos,wcnt,op,found,i,damaged;
	char *userfile_options[]={
		"version","password","promote_date","times","levels","general","user_set",
		"fighting","purging","last_site","mail_verify","description",
		"in_phrase","out_phrase","email","homepage","recap_name",
		"prompt", "nick_grm", "pueblo", "restrict", "ign_word", "*" /* KEEP HERE! */
		};

	set_crash();
	write_syslog(SYSLOG, 1, "Nahravam staru verziu userfajlu pre %s, v0.11 > 1.2.0\n", user->name);
	sprintf(fname,"%s/%s.D", USERFILES, user->name);
	if (!(fp=fopen(fname,"r"))) return 0;

	damaged=0;
	fgets(line,ARR_SIZE-1,fp);
	line[strlen(line)-1]='\0';

while (!feof(fp)) {
  /* make this into the functions own word array.  This allows this array to
     have a different length from the general words array. */
  wn=0; wpos=0;
  str=line;
  do {
    while (*str<33) if (!*str++) goto LUOUT;
    while (*str>32 && wpos<40) user_words[wn][wpos++]=*str++;
    user_words[wn++][wpos]='\0';
    wpos=0;
  } while (wn<16);
  wn--;
 LUOUT:
  wcnt=wn;
  /* now get the option we're on */
  op=0;  found=1;
  while (strcmp(userfile_options[op],user_words[0])) {
    if (userfile_options[op][0]=='*') { found=0; break; }
    op++;
    }
  if (found) {
    switch (op) {
      case 0:
	if (wcnt>=2) {      /* make sure more than just option string was there */
	  strcpy(user->version,remove_first(line));
	  }
	break;
      case 1:
	if (wcnt>=2) strcpy(user->pass,remove_first(line));
	break;
      case 2:
	if (wcnt>=2) strcpy(user->date,remove_first(line));
	break;
      case 3:
	for (i=1;i<wcnt;i++)
	  switch(i) {
	    case 1: user->last_login=(time_t)atoi(user_words[i]);  break;
	    case 2: user->total_login=(time_t)atoi(user_words[i]);  break;
	    case 3: user->last_login_len=atoi(user_words[i]);  break;
	    case 4: user->read_mail=(time_t)atoi(user_words[i]);  break;
	    }
	break;
      case 4:
	for (i=1;i<wcnt;i++)
	  switch(i) {
	    case 1: user->level=atoi(user_words[i]);  break;
	    case 2: user->unarrest=atoi(user_words[i]);  break;
	    case 3: user->arrestby=atoi(user_words[i]);  break;
	    case 4: user->muzzled=atoi(user_words[i]);  break;
	    }
	break;
      case 5:
	for (i=1;i<wcnt;i++)
	  switch(i) {
	    case 1: user->accreq=atoi(user_words[i]);  break;
	    case 2: user->command_mode=atoi(user_words[i]);  break;
	    case 3: user->prompt=atoi(user_words[i]);  break;
	    case 4: user->vis=atoi(user_words[i]);  break;
	    case 5: user->monitor=atoi(user_words[i]);  break;
	    case 6: user->mail_verified=atoi(user_words[i]);  break;
	    case 7: user->logons=atoi(user_words[i]);  break;
		case 8: user->terminal.xterm=atoi(user_words[i]);  break;
	    }
	break;
      case 6:
	for (i=1;i<wcnt;i++)
	  switch(i) {
	    case  1: user->gender=atoi(user_words[i]);  break;
	    case  2: user->age=atoi(user_words[i]);  break;
	    case  3: user->hideemail=atoi(user_words[i]);  break;
	    case  4: user->lroom=atoi(user_words[i]);  break;
	    case  5: user->alert=atoi(user_words[i]);  break;
	    case  6: user->autofwd=atoi(user_words[i]);  break;
	    case  7: user->show_pass=atoi(user_words[i]);  break;
	    case  8: user->show_rdesc=atoi(user_words[i]);  break;
	    case  9: user->cmd_type=atoi(user_words[i]);  break;
	    case 10: strcpy(user->icq, user_words[i]);  break;
	    case 11: user->who_type=atoi(user_words[i]); break;
	    }
	break;
      case 7:
	for (i=1;i<wcnt;i++)
	  switch(i) {
	    case 1: user->hits=atoi(user_words[i]);  break;
	    case 2: user->misses=atoi(user_words[i]);  break;
	    case 3: user->deaths=atoi(user_words[i]);  break;
	    case 4: user->kills=atoi(user_words[i]);  break;
	    case 5: user->bullets=atoi(user_words[i]);  break;
	    case 6: user->hps=atoi(user_words[i]);  break;
		case 7: user->money=atoi(user_words[i]); break;
		case 8: user->bank=atoi(user_words[i]); break;
	    }
	break;
      case 8:
	for (i=1;i<wcnt;i++)
	  switch(i) {
	    case 1: user->expire=atoi(user_words[i]);  break;
	    case 2: user->t_expire=(time_t)atoi(user_words[i]);  break;
	    }
	break;
      case  9:
	for (i=1;i<wcnt;i++)
	  switch(i) {
	    case 1: strcpy(user->last_site,user_words[i]);  break;
	    case 2: strcpy(user->logout_room,user_words[i]);  break;
	    }
	break;
      case 10:
	if (wcnt>=2) strcpy(user->verify_code,remove_first(line));
	break;
      case 11:
	if (wcnt>=2) strcpy(user->desc,remove_first(line));
	break;
      case 12:
	if (wcnt>=2) strcpy(user->in_phrase,remove_first(line));
	break;
      case 13:
	if (wcnt>=2) strcpy(user->out_phrase,remove_first(line));
	break;
      case 14:
	if (wcnt>=2) strcpy(user->email,remove_first(line));
	break;
      case 15:
	if (wcnt>=2) strcpy(user->homepage,remove_first(line));
	break;
      case 16:
	if (wcnt>=2) strcpy(user->recap,remove_first(line));
	break;
      case 17:
        for (i=1; i<wcnt; i++)
          switch(i) {
            case 1: strcpy(user->prompt_str, user_words[i]); break;
            }
        break;
      case 18:
        for (i=1; i<wcnt; i++)
          switch(i) {
            case 1: strcpy(user->nameg, user_words[i]); break;
            case 2: strcpy(user->named, user_words[i]); break;
            case 3: strcpy(user->namea, user_words[i]); break;
            case 4: strcpy(user->namel, user_words[i]); break;
            case 5: strcpy(user->namei, user_words[i]); break;
            case 6: strcpy(user->namex, user_words[i]); break;
            case 7: strcpy(user->namey, user_words[i]); break;
            case 8: strcpy(user->namez, user_words[i]); break;
            }
        break;
      case 19:
#ifdef PUEBLO
        for (i=1; i<wcnt; i++)
          switch (i) {
            case 1: user->pueblo_mm=atoi(user_words[i]); break;
            case 2: user->pueblo_pg=atoi(user_words[i]); break;
            case 3: user->voiceprompt=atoi(user_words[i]); break;
            }
#endif
        break;
      case 20:
        if (wcnt>=2) strcpy(user->restrict, remove_first(line));
        else strcpy(user->restrict, RESTRICT_MASK);
        break;
      case 21:
        if (wcnt>=2) user->ign_word=strdup(remove_first(line));
	break;
      default: damaged++; break;
      }
    }
  else damaged++;
  fgets(line,ARR_SIZE-1,fp);
  line[strlen(line)-1]=0;
  }
fclose(fp);
/* binarne ukladane data */
	sprintf(fname, "%s/bin/%s.D", USERFILES, user->name);
	if (!(fp=fopen(fname, "rb"))) return 0;
	fread(&user->ignore, sizeof(USER_IGNORE), 1, fp);
	fread(&user->terminal, sizeof(USER_TERMINAL), 1, fp);
	fclose(fp);

if (damaged) write_syslog(SYSLOG,1,"Poskodeny userfajl '%s.D'\n",user->name);
strcpy(user->recap,user->name);
strcpy(user->bw_recap,colour_com_strip(user->recap));
user->real_level=user->level;
if (user->level==ROOT && strcmp(user->name, reg_sysinfo[SYSOPUNAME])) {
	user->real_level=NEW;
	write_syslog(SYSLOG, 1, "~CRAutodemote~RS %s from %s to %s - edited userfile\n",
		user->name, user_level[user->level].name, user_level[user->real_level].name);
	sprintf(text, "~CRAutodemote~RS from %s to %s - edited userfile\n",
		user_level[user->level].name, user_level[user->real_level].name);
	add_history(user->name, 1, text);
	user->vis=1;
	add_user_date_node(user->name, long_date(1));
	user->unarrest=NEW;
	user->arrestby=ROOT;
	user->level=JAILED;
	user_list_level(user->name, user->level);
	strcpy(user->date, long_date(1));
	strcpy(user->site, user->last_site);
	save_user_details(user, 0);
	}
if (user->level>NEW) user->accreq=-1;   /* compensate for new accreq change */
get_macros(user);
get_xgcoms(user);
get_friends(user);
read_user_reminders(user);
return 1;
}

/*** Save the details for the user ***/
int save_user_details(UR_OBJECT user, int save_current)
{
	FILE *fp;
	char fname[FNAME_LEN];
	int i;

	set_crash();
#ifdef NETLINKS
	if (user->type==REMOTE_TYPE) return 0;
#endif
	if (user->type==CLONE_TYPE) return 0;
	sprintf(fname,"%s/%s.D", USERFILES, user->name);
	if (!(fp=fopen(fname,"w"))) {
		vwrite_user(user,"%s: chyba pri ukladani tvojich detailov.\n",syserror);
		write_syslog(ERRLOG,1,"SAVE_USER_STATS: pri ukladani detaijlov pre %s\n",user->name);
		return 0;
		}
	/* reset normal level */
	if (user->real_level<user->level) user->level=user->real_level;
	if (!strcmp(user->name, reg_sysinfo[SYSOPUNAME])) {
		user->level=user->real_level=ROOT;
		}
	/* print out the file */
	fprintf(fp,"version       %s\n", USERVER);     /* of user struct */
	fprintf(fp,"password      %s\n", user->pass);
	fprintf(fp,"promote_date  %s\n", user->date);
	if (save_current)
		fprintf(fp,"times         %d %d %d %d\n",
			(int)time(0), (int)user->total_login,
			(int)(time(0)-user->last_login), (int)user->read_mail);
	else
		fprintf(fp,"times         %d %d %d %d\n",
			(int)user->last_login, (int)user->total_login,
			user->last_login_len, (int)user->read_mail);
	fprintf(fp,"levels        %d %d %d %d\n",
		user->level, user->unarrest, user->arrestby, user->muzzled);
	fprintf(fp,"general       %d %d %d %d %d %d %d\n",
		user->accreq, user->command_mode,
		user->prompt, user->vis, user->monitor, user->mail_verified,
		user->logons);
	fprintf(fp,"user_set      %d %d %d %d %d %d %d %d %d %s %d\n",
		user->gender, user->age,
		user->hideemail, user->lroom, user->alert,
		user->autofwd, user->show_pass, user->show_rdesc,
		user->cmd_type, user->icq, user->who_type);
	fprintf(fp,"fighting      %d %d %d %d %d %d %d %d\n",
		user->hits, user->misses, user->deaths, user->kills,
		user->bullets, user->hps, user->money, user->bank);
	if (!save_current)
		fprintf(fp,"purging       %d %d\n",
			user->expire, (int)user->t_expire);
	else {
		if (user->level==NEW)
			fprintf(fp,"purging       %d %d\n",
				user->expire,(int)(time(0)+(NEWBIE_EXPIRES*86400)));
		else
			fprintf(fp,"purging       %d %d\n",
				user->expire,(int)(time(0)+(USER_EXPIRES*86400)));
		}
	if (save_current)
		fprintf(fp,"last_site     %s %s\n",
			user->site, user->room->name);
	else
		 fprintf(fp,"last_site     %s %s\n",
		 	user->last_site, user->logout_room);
	fprintf(fp,"mail_verify   %s\n", user->verify_code);
	fprintf(fp,"description   %s\n", user->desc);
	fprintf(fp,"in_phrase     %s\n", user->in_phrase);
	fprintf(fp,"out_phrase    %s\n", user->out_phrase);
	fprintf(fp,"email         %s\n", user->email);
	fprintf(fp,"homepage      %s\n", user->homepage);
	fprintf(fp,"recap_name    %s\n", user->recap);
	fprintf(fp,"prompt        %s\n", user->prompt_str);
	fprintf(fp,"nick_grm      %s %s %s %s %s %s %s %s\n",
		user->nameg, user->named, user->namea, user->namel, user->namei,
		user->namex, user->namey, user->namez);
#ifdef PUEBLO
	fprintf(fp,"pueblo        %d %d %d\n",
		user->pueblo_mm, user->pueblo_pg, user->voiceprompt);
#endif
	/* set default restriction for superior users */
	if (user->level>=MIN_LEV_AUTORST) {
		for (i=0; i<strlen(susers_restrict); i++)
			if (susers_restrict[i]!='.')
				user->restrict[i]=susers_restrict[i];
		}
	fprintf(fp,"restrict      %s\n", user->restrict);
	if (user->ign_word!=NULL)
		fprintf(fp,"ign_word      %s\n", user->ign_word);
	else fprintf(fp, "ign_word\n");
	fclose(fp);

/* cast s binarne ukladanymi datami */
	sprintf(fname, "%s/bin/%s.D", USERFILES, user->name);
	if (!(fp=fopen(fname, "wb"))) {
		vwrite_user(user,"%s: chyba pri ukladani tvojich detailov.\n",syserror);
		write_syslog(ERRLOG,1,"SAVE_USER_STATS: pri ukladani detailov pre %s - bin cast\n",user->name);
		return 0;
		}
	fwrite(&user->ignore, sizeof(USER_IGNORE), 1, fp);
	fwrite(&user->terminal, sizeof(USER_TERMINAL), 1, fp);
	fclose(fp);

	return 1;
}


/* count up how many users of a certain level and in total in the linked user list */
void count_users(void)
{
	struct user_dir_struct *entry;
	int i;

	set_crash();
/* first zero out all level counts */
	amsys->user_count=0;
	for (i=JAILED;i<=ROOT;i++)
		amsys->level_count[i]=0;
/* count up users */
	for (entry=first_dir_entry;entry!=NULL;entry=entry->next) {
		amsys->level_count[entry->level]++;
		amsys->user_count++;
		}
}



/* work out how many motds are stored - if an motd file is deleted after
   this count has been made then you need to recount them with the recount
   command.  If you fail to do this and something buggers up because the count
   is wrong then it's your own fault.
   */
int count_motds(int forcecnt)
{
	char fname[FNAME_LEN];
	DIR *dirp;
	struct dirent *dp; 
	int i;

	set_crash();
amsys->motd1_cnt=0;  amsys->motd2_cnt=0;
for (i=1;i<=2;i++) {
  /* open the directory file up */
  sprintf(fname,"%s/motd%d", MOTDFILES, i);
  if ((dirp=opendir(fname))==NULL) {
    switch (forcecnt) {
      case 0:
	fprintf(stderr,"Lotos: Chyba pri otvarani adresara v count_motds().\n");
	boot_exit(20);
      case 1: return 0;
      }
    }
  /* count up how many files in the directory - not including . and .. */
  while ((dp=readdir(dirp))!=NULL) {
    if (strstr(dp->d_name,"motd")) (i==1) ? ++amsys->motd1_cnt : ++amsys->motd2_cnt;
    }
  closedir(dirp);
  }
return 1;
}


/* return a random number for an motd file - if 0 then return 1 */
int get_motd_num(int motd)
{
	int num;

	srand(time(0));
	set_crash();
	if (!amsys->random_motds) return 1;
	switch (motd) {
		case 1: num=rand()%amsys->motd1_cnt+1;  break;
		case 2: num=rand()%amsys->motd2_cnt+1;  break;
		default: num=0;  break;
		}
	return (!num) ? 1:num;
}



/******************************************************************************
 File functions - reading, writing, counting of lines, etc
 *****************************************************************************/

/* wipes ALL the files belonging to the user with name given */
void clean_files(char *name)
{
	DIR *dirp;
	struct dirent *dp;
	char fname[FNAME_LEN];

	set_crash();
	name[0]=toupper(name[0]);
	sprintf(fname,"%s/%s.D", USERFILES, name);
	unlink(fname);
	sprintf(fname,"%s/bin/%s.D", USERFILES, name);
	unlink(fname);
	sprintf(fname,"%s/%s.M", USERMAILS, name);
	unlink(fname);
	sprintf(fname,"%s/%s.P", USERPROFILES, name);
	unlink(fname);
	sprintf(fname,"%s/%s.H", USERHISTORYS, name);
	unlink(fname);
	sprintf(fname,"%s/%s.C", USERCOMMANDS, name);
	unlink(fname);
	sprintf(fname,"%s/%s.MAC", USERMACROS, name);
	unlink(fname);
	sprintf(fname,"%s/%s.F", USERFRIENDS, name);
	unlink(fname);
	sprintf(fname,"%s/%s.R", USERROOMS, name);
	unlink(fname);
	sprintf(fname,"%s/%s.B", USERROOMS, name);
	unlink(fname);
	sprintf(fname,"%s/%s.K", USERROOMS, name);
	unlink(fname);
	sprintf(fname,"%s/%s.REM", USERREMINDERS, name);
	unlink(fname);
	strcpy(fname, USERPLDATAS);
	if ((dirp=opendir(fname))==NULL) {
		write_syslog(ERRLOG, 1, "Chyba pri otvarani adresara v clean_files()\n");
		return;
		}
	sprintf(fname, "%s.", name);
	while ((dp=readdir(dirp))!=NULL)
		if (!strncmp(dp->d_name, fname, strlen(fname))) {
			sprintf(text, "%s/%s", USERPLDATAS, dp->d_name);
			unlink(text);
			}
	closedir(dirp);
}


/* remove a line from the top or bottom of a file.
   where==0 then remove from the top
   where==1 then remove from the bottom 
 */
int remove_top_bottom(char *filename, int where)
{
	char line[ARR_SIZE];
	FILE *fpi, *fpo;
	int i,cnt;

	set_crash();
if (!(fpi=fopen(filename,"r"))) return 0;
if (!(fpo=fopen("temp_file","w"))) {
  fclose(fpi);  return 0;
  }
/* remove from top */
if (where==0) {
  /* get the first line */
  fgets(line,ARR_SIZE,fpi);
  /* get rest of file */
  fgets(line,ARR_SIZE,fpi);
  while(!feof(fpi)) {
    line[strlen(line)-1]='\0';
    fprintf(fpo,"%s\n",line);
    fgets(line,ARR_SIZE-1,fpi);
    }
  }
/* remove from bottom of file */
else {
  i=0;
  cnt=count_lines(filename);
  cnt--;
  fgets(line,ARR_SIZE,fpi);
  while(!feof(fpi)) {
    if (i<cnt) {
      line[strlen(line)-1]='\0';
      fprintf(fpo,"%s\n",line);
      }
    i++;
    fgets(line,ARR_SIZE-1,fpi);
    }
  }
fclose(fpi);  fclose(fpo);
rename("temp_file",filename);
if (!(cnt=count_lines(filename))) unlink(filename);
return 1;
}


/* counts how many lines are in a file */
int count_lines(char *fname)
{
	int i=0,c;
	FILE *fp;

	set_crash();
	if (!(fp=fopen(fname,"r"))) return i;
	c=getc(fp);
	while (!feof(fp)) {
		if (c=='\n') i++;
		c=getc(fp);
		}
	fclose(fp);
	return i;
}



/******************************************************************************
 Write functions - users, rooms, system logs
 *****************************************************************************/

/*** Write a NULL terminated string to a socket ***/
void write_sock(int sock, char *str)
{
	set_crash();
	write(sock,str,strlen(str));
}


/* a vargs wrapper for the write_user function.  This will enable you
   to send arguments directly to this function.
   before ya mention it, Squirt, I already had this in a file before your snippet...
   but I gotta admit that your snippet kicked my butt into actually implementing this ;)
*/
void vwrite_user(UR_OBJECT user, char *str, ...)
{
	va_list args;

	set_crash();
	vtext[0]='\0';
	va_start(args,str);
	vsprintf(vtext,str,args);
	va_end(args);
	write_user(user,vtext);
}


/*** Send message to user ***/
void write_user(UR_OBJECT user, char *str)
{
	int buffpos,sock,i,j, cnt;
	char *start,buff[OUT_BUFF_SIZE];
#ifdef NETLINKS
	char mesg[ARR_SIZE];
#endif

	set_crash();
	if (user==NULL) return;
#ifdef NETLINKS
	if (user->type==REMOTE_TYPE) {
		if (user->netlink->ver_major<=3 
			&& user->netlink->ver_minor<2) str=colour_com_strip(str);
		if (str[strlen(str)-1]!='\n') sprintf(mesg,"MSG %s\n%s\nEMSG\n",user->name,str);
		else sprintf(mesg,"MSG %s\n%sEMSG\n",user->name,str);
		write_sock(user->netlink->socket,mesg);
		return;
		}
#endif
	start=str;
	buffpos=0;
	sock=user->socket;
/* Process string and write to buffer. We use pointers here instead of arrays 
   since these are supposedly much faster (though in reality I guess it depends
   on the compiler) which is necessary since this routine is used all the 
   time. */
	cnt=0;
	while (*str) {
		if (*str=='\n') {
			if (buffpos>OUT_BUFF_SIZE-6) {
				write(sock,buff,buffpos);
				buffpos=0;
				}
    /* Reset terminal before every newline */
			memcpy(buff+buffpos,"\033[0m",4);
			buffpos+=4;
			if (user->terminal.txt
				|| user->terminal.revers
				|| user->terminal.bold) {
					memcpy(buff+buffpos, "\033[37m", 5);
					buffpos+=5;
				}
			if (user->terminal.bckg
				|| user->terminal.revers) {
					memcpy(buff+buffpos, "\033[40m", 5);
					buffpos+=5;
				}
   			*(buff+buffpos)='\n';
			*(buff+buffpos+1)='\r';  
			buffpos+=2;
			++str;
			cnt=0;
			}
		else if (user->terminal.wrap && cnt==SCREEN_WRAP) {
			*(buff+buffpos)='\n';
			*(buff+buffpos+1)='\r';  
			buffpos+=2;
			cnt=0;
			}
		else {  
    /* See if its a ^ before a ~ , if so then we print colour command
       as text */
			if (*str=='^' && *(str+1)=='~') {  ++str;  continue;  }
			if (str!=start && *str=='~' && *(str-1)=='^') {
				*(buff+buffpos)=*str;
				goto CONT;
				}
    /* Process colour commands eg ~FR. We have to strip out the commands 
       from the string even if user doesnt have colour switched on hence 
       the user->colour check isnt done just yet */
			if (*str=='~') {
			if (buffpos>OUT_BUFF_SIZE-6) {
				write(sock,buff,buffpos);
				buffpos=0;
				}
			++str;
			for (i=0;i<NUM_COLS;++i) {
				if (!strncmp(str, colour_codes[i].txt_code, 2)) {
					switch (i) {
						case  0: /* RS */
							memcpy(buff+buffpos,colour_codes[i].esc_code,strlen(colour_codes[i].esc_code));
							buffpos+=strlen(colour_codes[i].esc_code)-1;
							break;
						case  1: /* OL */
							if (user->terminal.bold) {
								memcpy(buff+buffpos,colour_codes[i].esc_code,strlen(colour_codes[i].esc_code));
								buffpos+=strlen(colour_codes[i].esc_code)-1;
								}
							else buffpos--;
							break;
						case  2: /* UL */
							if (user->terminal.underline) {
								memcpy(buff+buffpos,colour_codes[i].esc_code,strlen(colour_codes[i].esc_code));
								buffpos+=strlen(colour_codes[i].esc_code)-1;
								}
							else buffpos--;
							break;
						case  3: /* LI */
							if (user->terminal.blink) {
								memcpy(buff+buffpos,colour_codes[i].esc_code,strlen(colour_codes[i].esc_code));
								buffpos+=strlen(colour_codes[i].esc_code)-1;
								}
							else buffpos--;
							break;
						case  4: /* RV */
							if (user->terminal.revers) {
								memcpy(buff+buffpos,colour_codes[i].esc_code,strlen(colour_codes[i].esc_code));
								buffpos+=strlen(colour_codes[i].esc_code)-1;
								}
							else buffpos--;
							break;
						case  5: /* FK */
						case  6: /* FR */
						case  7: /* FG */
						case  8: /* FY */
						case  9: /* FB */
						case 10: /* FM */
						case 11: /* FT */
						case 12: /* FW */
							if (user->terminal.txt) {
								memcpy(buff+buffpos,colour_codes[i].esc_code,strlen(colour_codes[i].esc_code));
								buffpos+=strlen(colour_codes[i].esc_code)-1;
								}
							else buffpos--;
							break;
						case 13: /* BK */
						case 14: /* BR */
						case 15: /* BG */
						case 16: /* BY */
						case 17: /* BB */
						case 18: /* BM */
						case 19: /* BT */
						case 20: /* BW */
							if (user->terminal.bckg) {
								memcpy(buff+buffpos,colour_codes[i].esc_code,strlen(colour_codes[i].esc_code));
								buffpos+=strlen(colour_codes[i].esc_code)-1;
								}
							else buffpos--;
							break;
						case 21: /* BP */
							if (!user->ignore.beeps) {
								memcpy(buff+buffpos,colour_codes[i].esc_code,strlen(colour_codes[i].esc_code));
								buffpos+=strlen(colour_codes[i].esc_code)-1;
								}
							else buffpos--;
							break;
						case 22: /* CS */
							if (user->terminal.clear) {
								memcpy(buff+buffpos,colour_codes[i].esc_code,strlen(colour_codes[i].esc_code));
								buffpos+=strlen(colour_codes[i].esc_code)-1;
								}
							else {
								for (j=0; j<50; j++) {
									memcpy(buff+buffpos, "\n", strlen("\n"));
									buffpos+=strlen("\n")-1;
									}
								}
							break;
						case 23: /* MS */
						case 24: /* MM */
							if (user->terminal.music) {
								memcpy(buff+buffpos,colour_codes[i].esc_code,strlen(colour_codes[i].esc_code));
								buffpos+=strlen(colour_codes[i].esc_code)-1;
								}
							else buffpos--;
							break;
						case 25: /* CK */
						case 26: /* CR */
						case 27: /* CG */
						case 28: /* CY */
						case 29: /* CB */
						case 30: /* CM */
						case 31: /* CT */
						case 32: /* CW */
							if (user->terminal.txt && user->terminal.bold) {
								memcpy(buff+buffpos,colour_codes[i].esc_code,strlen(colour_codes[i].esc_code));
								buffpos+=strlen(colour_codes[i].esc_code)-1;
								}
							else if (user->terminal.txt) {
								memcpy(buff+buffpos,colour_codes[i-20].esc_code,strlen(colour_codes[i-20].esc_code));
								buffpos+=strlen(colour_codes[i-20].esc_code)-1;
								}
							else if (user->terminal.bold) {
								memcpy(buff+buffpos,colour_codes[1].esc_code,strlen(colour_codes[1].esc_code));
								buffpos+=strlen(colour_codes[1].esc_code)-1;
								}
							else buffpos--;
							break;
						}
					++str;
					--cnt;
					goto CONT;
					}
				}
			*(buff+buffpos)=*(--str);
			}
		else *(buff+buffpos)=*str;
CONT:
		++buffpos;
		++str;
		cnt++;
		}
	if (buffpos==OUT_BUFF_SIZE) {
			write(sock,buff,OUT_BUFF_SIZE);
			buffpos=0;
			}
		}
	if (buffpos) write(sock,buff,buffpos);
/* Reset terminal at end of string */
	write_sock(sock,"\033[0m");
	if (user->terminal.txt
		|| user->terminal.bold
		|| user->terminal.revers) write_sock(sock, "\033[37m");
	if (user->terminal.bckg
		|| user->terminal.revers) write_sock(sock, "\033[40m"); 
}

/*** Write to users of level 'level' and above or below depending on above
     variable; if 1 then above else below.  If user given then ignore that user
     when writing to their level.
     ***/
void write_level(int level, int above, char *str, UR_OBJECT user)
{
	UR_OBJECT u;

	set_crash();
	for (u=user_first;u!=NULL;u=u->next) {
		if ((check_igusers(u,user))!=-1 && user->level<GOD) continue;
		if ((u->ignore.wiz && (com_num==WIZSHOUT || com_num==WIZEMOTE)) || (u->ignore.logons && logon_flag)) continue;
		if (u!=user && !u->login && u->type!=CLONE_TYPE) {
			if ((above && u->level>=level) || (!above && u->level<=level)) {
				if (u->afk) {
					record_afk(u,str);
					continue;
					}
				if (u->editing) {
					record_edit(u,str);
					continue;
					}
				if (!u->ignore.all && !u->editing) write_user(u,str);
				record_tell(u,str);
				}
			}
		}
}


/* a vargs wrapper for the write_room function.  This will enable you
   to send arguments directly to this function 
   This is more a subsid than a wrapper as it doesn't directly call write_room
*/
void vwrite_room(RM_OBJECT rm, char *str, ...)
{
	va_list args;

	set_crash();
	vtext[0]='\0';
	va_start(args,str);
	vsprintf(vtext,str,args);
	va_end(args);
	write_room_except(rm,vtext,NULL);
}


/*** Subsid function to below but this one is used the most ***/
void write_room(RM_OBJECT rm, char *str)
{
	set_crash();
	write_room_except(rm,str,NULL);
}


/* a vargs wrapper for the write_room_except function.  This will enable you
   to send arguments directly to this function 
*/
void vwrite_room_except(RM_OBJECT rm, UR_OBJECT user, char *str, ...)
{
	va_list args;

	set_crash();
	vtext[0]='\0';
	va_start(args,str);
	vsprintf(vtext,str,args);
	va_end(args);
	write_room_except(rm,vtext,user);
}


/*** Write to everyone in room rm except for "user". If rm is NULL write 
     to all rooms. ***/
void write_room_except(RM_OBJECT rm, char *str, UR_OBJECT user)
{
	UR_OBJECT u;
	char text2[ARR_SIZE*2];

	set_crash();
for(u=user_first;u!=NULL;u=u->next) {
  if (u->login 
      || u->room==NULL 
      || (u->room!=rm && rm!=NULL) 
      || (u->ignore.all && !force_listen)
      || (u->ignore.shouts && (com_num==SHOUT || com_num==SEMOTE || com_num==SHOUTTO))
      || (u->ignore.logons && logon_flag)
      || (u->ignore.greets && com_num==GREET)
      || u==user) continue;
  if ((check_igusers(u,user))!=-1 && user->level<ARCH) continue;
  if (u->type==CLONE_TYPE) {
    if (u->clone_hear==CLONE_HEAR_NOTHING || u->owner->ignore.all) continue;
    /* Ignore anything not in clones room, eg shouts, system messages
       and semotes since the clones owner will hear them anyway. */
    if (rm!=u->room) continue;
    if (u->clone_hear==CLONE_HEAR_SWEARS) {
      if (!contains_swearing(str)) continue;
      }
    sprintf(text2, "~FT[ %s ]:~RS %s",u->room->name,str);
    write_user(u->owner, text2);
    }
  else write_user(u,str);
  } /* end for */
}


/*** Write to everyone on the users friends list
     if revt=1 then record to the friends tell buffer
     ***/
void write_friends(UR_OBJECT user, char *str, int revt)
{
	UR_OBJECT u;

	set_crash();
	for (u=user_first;u!=NULL;u=u->next) {
  if (u->login 
      || u->room==NULL
      || u->type==CLONE_TYPE
      || (u->ignore.all && !force_listen)
      || u==user) continue;
  if ((check_igusers(u,user))!=-1 && user->level<GOD) continue;
  if (!(user_is_friend(user,u))) continue;
  write_user(u,str); 
  if (revt) record_tell(u,str);
  } /* end for */
}


/*** Write a string to system log 
     type = what syslog to write to
     write_time = whether or not you have a time stamp imcluded
     str = string passed - possibly with %s, %d, etc
     ... = variable length args passed
***/
void write_syslog(int type, int write_time, char *str, ...)
{
	FILE *fp;
	int i=0;
	va_list args;
	char fname[FNAME_LEN];
	char ext[9];

	set_crash();
	fp=NULL;
	vtext[0]='\0';
	sprintf(ext, "%04d%02u%02u", tyear, tmonth+1, tmday);
	switch (type) {
		case SYSLOG:
			sprintf(fname,"%s/%s.%s", LOGFILES,MAINSYSLOG,ext);
			if (!BIT_TEST(amsys->logging,SYSLOG) || !(fp=fopen(fname,"a"))) return;
			break;
		case REQLOG:
			sprintf(fname,"%s/%s.%s", LOGFILES,REQSYSLOG,ext);
			if (!BIT_TEST(amsys->logging,REQLOG) || !(fp=fopen(fname,"a"))) return;
			break;
#ifdef DEBUG
		case DEBLOG:
			sprintf(fname,"%s/%s.%s", LOGFILES,DEBSYSLOG,ext);
			if (!BIT_TEST(amsys->logging,DEBLOG) || !(fp=fopen(fname,"a"))) return;
			break;
#endif
		case ERRLOG:
			sprintf(fname,"%s/%s.%s", LOGFILES,ERRSYSLOG,ext);
			if (!BIT_TEST(amsys->logging,ERRLOG) || !(fp=fopen(fname,"a"))) return;
			break;
#ifdef NETLINKS
		case NETLOG:
			sprintf(fname,"%s/%s.%s", LOGFILES,NETSYSLOG,ext);
			if (!BIT_TEST(amsys->logging,NETLOG) || !(fp=fopen(fname,"a"))) return;
			break;
#endif
		}
	va_start(args,str);
	if (write_time) {
		sprintf(vtext,"%02d/%02d %02d:%02d:%02d: ",tmday,tmonth+1,thour,tmin,tsec);
		i=strlen(vtext);
		vsprintf(vtext+i,str,args);
		}
	else vsprintf(vtext,str,args);
	va_end(args);
	fputs(vtext,fp);
	fclose(fp);
}


/* this version of the the last command log - the two procedures below - are
   thanks to Karri (The Bat) Kalpio who makes KTserv */

/* record the last command executed - helps find crashes */
void record_last_command(UR_OBJECT user, int comnum, int len)
{
	set_crash();
	sprintf(cmd_history[amsys->last_cmd_cnt & 15],"[%5d] %02d/%02d, %02d:%02d:%02d - %-15s - %3d/%-2d - %s",
	amsys->last_cmd_cnt,tmday,tmonth+1,thour,tmin,tsec,(comnum!=999)?command_table[comnum].name:"pbloenh",len,word_count,user->name);
	amsys->last_cmd_cnt++;
}


/* write the commands to the files */
void dump_commands(int foo)
{
	FILE *fp;
	char fname[FNAME_LEN];

	set_crash();
	sprintf(fname,"%s/%s.%04d%02u%02u", LOGFILES,LAST_CMD, tyear, tmonth+1, tmday);
	if ((fp=fopen(fname, "w"))) {
		int i,j;
		for (i=((j=amsys->last_cmd_cnt-16)>0?j:0); i<amsys->last_cmd_cnt; i++)
			fprintf(fp, "%s\n", cmd_history[i&15]);
		fclose(fp);
		}
}  


/*** shows the name of a user if they are invis.  Records to tell buffer if rec=1 ***/
void write_monitor(UR_OBJECT user, RM_OBJECT rm, int rec)
{
UR_OBJECT u;

	set_crash();
	for (u=user_first;u!=NULL;u=u->next) {
		if (u==user || u->login || u->type==CLONE_TYPE) continue;
		if (u->level<command_table[MONITOR].level || !u->monitor) continue;
		if (u->room==rm || rm==NULL) {
			if (!u->ignore.all && !u->editing) vwrite_user(u,"~BB~FG[%s]~RS ",user->name);
			if (rec) record_tell(u,text);
			}
		} /* end for */
}


/*** Page a file out to user. Colour commands in files will only work if 
     user!=NULL since if NULL we dont know if his terminal can support colour 
     or not. Return values: 
       0 = cannot find file, 1 = found file, 2 = found and finished ***/
int more(UR_OBJECT user, int sock, char *fname)
{
	int i,j,buffpos,num_chars,lines,retval,len,cnt,pager,fsize,fperc;
	char buff[OUT_BUFF_SIZE],text2[83],*str;
	struct stat stbuf;
	FILE *fp;

	set_crash();
/* check if file exists */
	if (!(fp=fopen(fname,"r"))) {
		if (user!=NULL) user->filepos=0;  
		return 0;
		}
/* get file size */
	if (stat(fname,&stbuf)==-1) fsize=0;
	else fsize=stbuf.st_size;
/* jump to reading posn in file */
	if (user!=NULL) fseek(fp,user->filepos,0);
	if (user==NULL) pager=23;
	else {
		if (user->terminal.pager<MAX_LINES || user->terminal.pager>99) pager=23;
		else pager=user->terminal.pager;
		}
	text[0]='\0';  
	buffpos=0;  
	num_chars=0;
	retval=1; 
	len=0;
	cnt=0;

/* If user is remote then only do 1 line at a time */
	if (sock==-1) {
		lines=1;
		fgets(text2,82,fp);
		}
	else {
		lines=0;
		fgets(text,sizeof(text)-1,fp);
		}

/* Go through file */
	while(!feof(fp) && (lines<pager || user==NULL)) {
#ifdef NETLINKS
		if (sock==-1) {
			lines++;  
			if (user->netlink->ver_major<=3 && user->netlink->ver_minor<2) str=colour_com_strip(text2);
			else str=text2;
			if (str[strlen(str)-1]!='\n') sprintf(text,"MSG %s\n%s\nEMSG\n",user->name,str);
			else sprintf(text,"MSG %s\n%sEMSG\n",user->name,str);
			write_sock(user->netlink->socket,text);
			num_chars+=strlen(str);
			fgets(text2,82,fp);
			continue;
			}
#endif
		str=text;
  /* Process line from file */
		while (*str) {
			if (*str=='\n') {
				if (buffpos>OUT_BUFF_SIZE-6) {
					write(sock,buff,buffpos);
					buffpos=0;
					}
      /* Reset terminal before every newline */
				if (user!=NULL) {
					memcpy(buff+buffpos,"\033[0m",4);
					buffpos+=4;
					if (user->terminal.txt
						|| user->terminal.revers
						|| user->terminal.bold) {
							memcpy(buff+buffpos, "\033[37m", 5);
							buffpos+=5;
						}
					if (user->terminal.bckg
						|| user->terminal.revers) {
							memcpy(buff+buffpos, "\033[40m", 5);
							buffpos+=5;
						}
					}
				*(buff+buffpos)='\n';
				*(buff+buffpos+1)='\r';  
				buffpos+=2;
				++str;
				cnt=0;
				}
			else if (user!=NULL && user->terminal.wrap && cnt==SCREEN_WRAP) {
				*(buff+buffpos)='\n';
				*(buff+buffpos+1)='\r';  
				buffpos+=2;
				cnt=0;
				}
			else {
      /* Process colour commands in the file. See write_user()
	 function for full comments on this code. */
				if (*str=='^' && *(str+1)=='~') {  ++str;  continue;  }
				if (str!=text && *str=='~' && *(str-1)=='^') {
					*(buff+buffpos)=*str;
					goto CONT;
					}
				if (*str=='~') {
					++str;
	/* process if user name variable */
					if (*str=='$') {
						if (buffpos>OUT_BUFF_SIZE-USER_NAME_LEN) {
							write(sock,buff,buffpos);
							buffpos=0;
							}
						if (user!=NULL) {
							memcpy(buff+buffpos,user->bw_recap,strlen(user->bw_recap));
							buffpos+=strlen(user->bw_recap)-1;
							cnt+=strlen(user->bw_recap)-1;
							}
						else {
							buffpos--;
							cnt--;
							}
						goto CONT;
						}
	/* process if colour variable */
					if (buffpos>OUT_BUFF_SIZE-6) {
						write(sock,buff,buffpos);
						buffpos=0;
						}
	/* ++str; */
					for (i=0;i<NUM_COLS;++i) {
						if (!strncmp(str,colour_codes[i].txt_code,2)) {
							if (user!=NULL) {
								switch (i) {
									case 0: /* RS */
										memcpy(buffpos+buff,colour_codes[i].esc_code,strlen(colour_codes[i].esc_code));
										buffpos+=strlen(colour_codes[i].esc_code)-1;
										break;
									case 1: /* OL */
										if (user->terminal.bold) {
											memcpy(buffpos+buff,colour_codes[i].esc_code,strlen(colour_codes[i].esc_code));
											buffpos+=strlen(colour_codes[i].esc_code)-1;
											}
										else buffpos--;
										break;
									case 2: /* UL */
										if (user->terminal.underline) {
											memcpy(buffpos+buff,colour_codes[i].esc_code,strlen(colour_codes[i].esc_code));
											buffpos+=strlen(colour_codes[i].esc_code)-1;
											}
										else buffpos--;
										break;
									case 3: /* LI */
										if (user->terminal.blink) {
											memcpy(buffpos+buff,colour_codes[i].esc_code,strlen(colour_codes[i].esc_code));
											buffpos+=strlen(colour_codes[i].esc_code)-1;
											}
										else buffpos--;
										break;
									case 4: /* RV */
										if (user->terminal.revers) {
											memcpy(buffpos+buff,colour_codes[i].esc_code,strlen(colour_codes[i].esc_code));
											buffpos+=strlen(colour_codes[i].esc_code)-1;
											}
										else buffpos--;
										break;
									case 5: /* FK */
									case 6: /* FR */
									case 7: /* FG */
									case 8: /* FY */
									case 9: /* FB */
									case 10:/* FM */
									case 11:/* FT */
									case 12:/* FW */
										if (user->terminal.txt) {
											memcpy(buffpos+buff,colour_codes[i].esc_code,strlen(colour_codes[i].esc_code));
											buffpos+=strlen(colour_codes[i].esc_code)-1;
											}
										else buffpos--;
										break;
									case 13: /* BK */
									case 14: /* BR */
									case 15: /* BG */
									case 16: /* BY */
									case 17: /* BB */
									case 18: /* BM */
									case 19: /* BT */
									case 20: /* BW */
										if (user->terminal.bckg) {
											memcpy(buffpos+buff,colour_codes[i].esc_code,strlen(colour_codes[i].esc_code));
											buffpos+=strlen(colour_codes[i].esc_code)-1;
											}
										else buffpos--;
										break;
									case 21: /* BP */
										if (!user->ignore.beeps) {
											memcpy(buffpos+buff,colour_codes[i].esc_code,strlen(colour_codes[i].esc_code));
											buffpos+=strlen(colour_codes[i].esc_code)-1;
											}
										else buffpos--;
										break;
									case 22: /* CS */
										if (user->terminal.clear) {
											memcpy(buffpos+buff,colour_codes[i].esc_code,strlen(colour_codes[i].esc_code));
											buffpos+=strlen(colour_codes[i].esc_code)-1;
											}
										else {
											for (j=0; j<50; j++) {
												memcpy(buffpos+buff, "\n", strlen("\n"));
												buffpos+=strlen("\n")-1;
												}
											}
										break;
									case 23: /* MS */
									case 24: /* ME */
										if (user->terminal.music) {
											memcpy(buffpos+buff,colour_codes[i].esc_code,strlen(colour_codes[i].esc_code));
											buffpos+=strlen(colour_codes[i].esc_code)-1;
										}
										else buffpos--;
										break;
									case 25: /* CK */
									case 26: /* CR */
									case 27: /* CG */
									case 28: /* CY */
									case 29: /* CB */
									case 30: /* CM */
									case 31: /* CT */
									case 32: /* CW */
										if (user->terminal.txt && user->terminal.bold) {
											memcpy(buffpos+buff,colour_codes[i].esc_code,strlen(colour_codes[i].esc_code));
											buffpos+=strlen(colour_codes[i].esc_code)-1;
											}
										else if (user->terminal.txt) {
											memcpy(buffpos+buff,colour_codes[i-20].esc_code,strlen(colour_codes[i-20].esc_code));
											buffpos+=strlen(colour_codes[i-20].esc_code)-1;
											}
										else if (user->terminal.bold) {
											memcpy(buffpos+buff,colour_codes[1].esc_code,strlen(colour_codes[1].esc_code));
											buffpos+=strlen(colour_codes[1].esc_code)-1;
											}
										else buffpos--;
										break;
									}
								}
							else buffpos--;
							++str;
							--cnt;
							goto CONT;
							}
						}
					*(buff+buffpos)=*(--str);
					}
				else *(buff+buffpos)=*str;
CONT:
				++buffpos;
				++str;
				++cnt;
				}
			if (buffpos==OUT_BUFF_SIZE) {
				write(sock,buff,OUT_BUFF_SIZE);
				buffpos=0;
				}
			}
		len=strlen(text);
		num_chars+=len;
		lines+=len/80+(len<80);
		fgets(text,sizeof(text)-1,fp);
		}
	if (buffpos && sock!=-1) write(sock,buff,buffpos);

/* if user is logging on dont page file */
	if (user==NULL) {
		fclose(fp);
		return 2;
		write_sock(sock,"\n");
		};
	if (feof(fp)) {
		user->filepos=0;
		no_prompt=0;
		retval=2;
		for (i=0;i<MAX_PAGES;i++) user->pages[i]=0;
		user->pagecnt=0;
		write_user(user,"\n");
		}
	else  {
  /* store file position and file name */
		user->filepos+=num_chars;
		user->pages[++user->pagecnt]=user->filepos;
		strcpy(user->page_file,fname);
  /* work out % of file displayed */
		fperc=(int)(user->filepos*100)/fsize;
  /* We use E here instead of Q because when on a remote system and
     in COMMAND mode the Q will be intercepted by the home system and 
     quit the user */
		vwrite_user(user, more_prompt, fperc);
		no_prompt=1;
		}
	fclose(fp);
	return retval;
}


/*** Page out a list of users of the level given.  If lev is -1 then page out
     all of the users
     ***/
int more_users(UR_OBJECT user)
{
	struct user_dir_struct *entry=NULL;
	int i,lines=0,retval=1;

	set_crash();
/* page all of the users */
if (first_dir_entry==NULL) return 0;
if (user->user_page_lev==-1) {
  /* get to where user is so far */
  if (!user->user_page_pos) entry=first_dir_entry;
  else for (i=0;i<user->user_page_pos;i++) entry=entry->next;
  while (entry!=NULL) {
    if (lines>=user->terminal.pager) {
      write_user(user, continue2);
      no_prompt=1;
      user->misc_op=16;
      user->status='R';
      return retval;
      }
    vwrite_user(user,"%d) %-*s : %s\n",entry->level,USER_NAME_LEN,entry->name,entry->date);
    entry=entry->next;
    user->user_page_pos++;
    lines++;
    } /* end while */
  retval=2;
  user->user_page_pos=0;  user->user_page_lev=0;  user->misc_op=0;
  user->status='a';
  return retval;
  } /* end if for listing all users */

/* list only those users of a specific level */
if (!amsys->level_count[user->user_page_lev]) return 0;
if (!user->user_page_pos) entry=first_dir_entry;
else {
  /* get to the position of the user level */
  entry=first_dir_entry;
  i=0;
  while (entry!=NULL) {
    if (entry->level!=user->user_page_lev) {
      entry=entry->next;
      continue;
      }
    if (i==user->user_page_pos) break;
    ++i;
    entry=entry->next;
    }
  }
lines=0;
while (entry!=NULL) {
  if (entry->level!=user->user_page_lev) {
    entry=entry->next;
    continue;
    }
  if (lines>=user->terminal.pager) {
    write_user(user, continue2);
    no_prompt=1;
    return retval;
    }
  /* doesn't matter if didn't boot in verbose mode as entry->date will be null anyway */
  vwrite_user(user,"%-*s : %s\n",USER_NAME_LEN,entry->name,entry->date);
  entry=entry->next;
  user->user_page_pos++;
  lines++;
  } /* end while */
write_user(user,"\n");
retval=2;
user->user_page_pos=0;  user->user_page_lev=0;  user->misc_op=0;
user->status='a';
return retval;
}


/* adds a string to the user's history list */
void add_history(char *name, int showtime, char *str)
{
	FILE *fp;
	char fname[FNAME_LEN];

	set_crash();
	name[0]=toupper(name[0]);
/* add to actual history listing */
	sprintf(fname,"%s/%s.H", USERHISTORYS,name);
	if ((fp=fopen(fname,"a"))) {
		if (!showtime) fprintf(fp,"%s",str);
		else fprintf(fp,"%02d/%02d %02d:%02d: %s",tmday,tmonth+1,thour,tmin,str);
		fclose(fp);
		write_syslog(SYSLOG,1,"HISTORY added for %s.\n",name);
		}
}



/******************************************************************************
 Logon/off functions
 *****************************************************************************/

/*** Login function. Lots of nice inline code :) ***/
void login(UR_OBJECT user, char *inpstr)
{
	UR_OBJECT u;
	int i;
	char name[ARR_SIZE],passwd[ARR_SIZE],motdname[500];

	set_crash();
	name[0]='\0';
	passwd[0]='\0';

	switch (user->login) {
		case LOGIN_NAME:
#ifdef PUEBLO
			if (syspp->pueblo_enh && user->pueblo!=-1) {
				if (!strncmp(inpstr,"PUEBLOCLIENT",12)) {
					user->pueblo = -1; /* Set to -1 so we don't keep repeating the welcome screen */
					cls(user);
					vwrite_user(user, "</xch_mudtext><center><img src=\"%s%s%s\"></center><xch_mudtext>",reg_sysinfo[TALKERHTTP],reg_sysinfo[PUEBLOWEB],reg_sysinfo[PUEBLOPIC]);
					vwrite_user(user, "</xch_mudtext><br><br><center><b><font size=+3>Welcome to %s v%s !</font></b><br><font size=+1>Lotos verzia %s</font></center><br><xch_mudtext>\n",reg_sysinfo[TALKERNAME], TVERSION, OSSVERSION);
					sprintf(text,"%s<>~RS %sMultimedia client has been Auto-detected.\n",colors[CWARNING],colors[CSYSBOLD]);
					write_duty(ARCH,text,NULL,NULL,2);
					user->login=LOGIN_NAME;
					name[0]='\0';
					write_user(user, login_prompt);
					return; 
					}
 				}
#endif
			sscanf(inpstr,"%s",name);
			if(name[0]<33) {
				write_user(user, login_prompt);
				return;
				}
			if (!strcmp(name,"quit")) {
				write_user(user, login_quit);
				disconnect_user(user);
				return;
				}
			if (!strcmp(name,"who")) {
      /* if you don't like this logon who, then replace it with the normal
	 one of who(user,0); */
				login_who(user);
				write_user(user, login_prompt);
				return;
				}
			if (!strcasecmp(name,"version")) {
				vwrite_user(user,"\n%s v%s (Lotos v%s (AmNUTS v%s (NUTS v%s)))\n",
					reg_sysinfo[TALKERNAME], TVERSION, OSSVERSION, AMNUTSVER, NUTSVER);
				write_user(user, login_prompt);
				return;
				}
			if (strlen(name)<USER_MIN_LEN) {
				write_user(user, login_shortname);  
				attempts(user);
				return;
				}
			if (strlen(name)>USER_NAME_LEN) {
				write_user(user, login_longname);
				attempts(user);
				return;
				}
    /* see if only letters in login */
    for (i=0;i<strlen(name);++i) {
      if (!isalpha(name[i])) {
	write_user(user, login_lettersonly);
	attempts(user);  return;
        }
      }
    if (contains_swearing(name)) {
      write_user(user, login_swname);
      attempts(user);  return;
      }
    strtolower(name);
    name[0]=toupper(name[0]);
    if (user_banned(name) && strcmp(name, reg_sysinfo[SYSOPUNAME])) {
      write_user(user, user_banned_prompt);
      sprintf(text, "%s<>~RS %sPokus o login zabanovaneho usera!~RS%s [%s] (%s:%d)\n",
		colors[CWARNING], colors[CSYSBOLD], colors[CSYSTEM], name, user->site, user->site_port);
	write_duty(ARCH, text, NULL, NULL, 2);
      disconnect_user(user);
      write_syslog(SYSLOG,1,"Pokus o login zabanovaneho usera %s.\n",name);
      return;
      }
    strcpy(user->name,name);
    strtolower(name);
#ifdef PUEBLO
    if (!strcmp(name, "puebloclient")) {
    	write_user(user, login_pbloname);
    	return;
    	}
#endif
    /* If user has hung on another login clear that session */
    for(u=user_first;u!=NULL;u=u->next) {
      if (u->login && u!=user && !strcmp(u->name,user->name)) {
	disconnect_user(u);  break;
        }
      }
    if (!load_user_details(user)) {
      /* test na ROOTovsky login */
      if (!strcmp(user->name, reg_sysinfo[SYSOPUNAME])) {
      	user->level=ROOT;
      	strcpy(user->pass, reg_sysinfo[SYSOPPASSWD]);
      	}
      /* we presume that port 1 is the wizport */
      if (user->port==port[1]) {
	write_user(user, login_nonewatwiz);
	disconnect_user(user);  
	return;
        }
      if (amsys->minlogin_level>-1) {
	write_user(user, login_nonewacc);
	disconnect_user(user);  
	return;
        }
      if (site_banned(user->site,1) && user->level<ROOT) {
	write_user(user, login_nonewatbanned);
	write_syslog(SYSLOG,1,"Attempted login by a new user from banned new users site %s.\n",user->site);
	disconnect_user(user);
	return;
        }
      if (user->level<ROOT) {
        vwrite_user(user, login_welcome, reg_sysinfo[TALKERNAME]);
        write_user(user, login_new_user);
        }
      }
    else {
      if (!strcmp(user->name, reg_sysinfo[SYSOPUNAME])) user->level=ROOT;
      if (user->port==port[1] && user->level<amsys->wizport_level) {
	vwrite_user(user, login_minwizlev,user_level[amsys->wizport_level].name);
	disconnect_user(user);  
	return;
        }
      if (user->level<amsys->minlogin_level) {
	write_user(user, login_minlev);
	disconnect_user(user);  
	return;
        }
      }
	if (user->terminal.xterm && !user->attempts)
		vwrite_user(user, "\033]0;%s\007", reg_sysinfo[TALKERNAME]);
    write_user(user, password_prompt);
    echo_off(user);
    user->login=LOGIN_PASSWD;
    return;

  case LOGIN_PASSWD:
    sscanf(inpstr,"%s",passwd);
    if (strlen(passwd)<PASS_MIN_LEN) {
      write_user(user, password_short);  
      attempts(user);
      return;
      }
    if (strlen(passwd)>PASS_LEN) {
      write_user(user, password_long);
      attempts(user);  return;
      }
    /* if new user... */
    if (!user->pass[0]) {
      strcpy(user->pass,(char *)crypt(passwd,crypt_salt));
      write_user(user,"\n");
      if (more(NULL,user->socket,RULESFILE)) {
	write_user(user, login_rules_prompt);
        }
      write_user(user, password_again);
      user->login=LOGIN_CONFIRM;
      }
    else {
      if (!strcmp(user->pass,(char *)crypt(passwd,crypt_salt))) {
	echo_on(user);
	amsys->logons_old++;
	/* Instead of connecting the user with:  'connect_user(user);  return;'
	   Show the user the MOTD2 so that they can read it.  If you wanted, you
	   could make showing the MOTD2 optional, in which case use an 'if' clause
	   to either do the above or the following...
	   */
	cls(user);
	/* If there is no motd2 files then don't display them */
	if (amsys->motd2_cnt) {
	  sprintf(motdname,"%s/motd2/motd%d", MOTDFILES,(get_motd_num(2)));
	  if (!show_file(user,motdname)) {
	  	write_syslog(ERRLOG, 1, "nemozem zobrazit: %s\n", motdname);
	  	}
	  }
	vwrite_user(user, "%s~RS pouziva ~FT~OLLotos~FW v~FR%s~RS - S/N %s (%s)\n\n",
		reg_sysinfo[TALKERNAME], OSSVERSION, reg_sysinfo[SERIALNUM], reg_sysinfo[REGUSER]);
	write_user(user, enterprompt);
	user->login=LOGIN_PROMPT;
	return;
        }
      write_user(user, password_wrong);
      attempts(user);
      }
    return;

  case LOGIN_CONFIRM:
    sscanf(inpstr,"%s",passwd);
    if (strcmp(user->pass,(char*)crypt(passwd,crypt_salt))) {
      write_user(user, password_nomatch);
      attempts(user);
      return;
      }
    echo_on(user);
	nick_grm(user);
    strcpy(user->desc, default_desc);
    strcpy(user->in_phrase, default_inphr);
    strcpy(user->out_phrase, default_outphr);
    strcpy(user->date,(long_date(1)));
    strcpy(user->recap,user->name);
    strcpy(user->bw_recap,colour_com_strip(user->recap));
    user->last_site[0]='\0';
    user->level=NEW;
    user->unarrest=NEW;
    user->muzzled=0;
    user->command_mode=0;
    user->prompt=amsys->prompt_def;
    user->terminal.txt=amsys->colour_def;
    user->terminal.checho=amsys->charecho_def;
    save_user_details(user,1);
    add_user_node(user->name,user->level);
    add_user_date_node(user->name,(long_date(1)));
    add_history(user->name,1,"Was initially created.\n");
#ifdef PUEBLO
    user->pueblo_mm=syspp->pblo_usr_mm_def;
    user->pueblo_pg=syspp->pblo_usr_pg_def;
#endif
    strcpy(user->restrict, RESTRICT_MASK);
    write_syslog(SYSLOG,1,"Novy juzer \"%s\" vytvoreny.\n",user->name);
    amsys->logons_new++;
    amsys->level_count[user->level]++;
    /* Check out above for explaination of this */
    cls(user);
    /* If there is no motd2 files then don't display them */
    if (amsys->motd2_cnt) {
      sprintf(motdname,"%s/motd2/motd%d", MOTDFILES, (get_motd_num(2)));
      more(user,user->socket,motdname);
      } 
    write_user(user, enterprompt);
    user->login=LOGIN_PROMPT;
    return;

  case LOGIN_PROMPT:
    if(user->level==ROOT) user->accreq=-1;
    user->login=0;
    write_user(user,"\n\n");
    connect_user(user);
    return;
  } /* end switch */
}
	


/*** Count up attempts made by user to login ***/
void attempts(UR_OBJECT user)
{
	set_crash();
	user->attempts++;
	if (user->attempts==LOGIN_ATTEMPTS) {
		write_user(user, login_attempts);
		disconnect_user(user);
		if (load_user_details(user)) {
			sprintf(text, "~FR~OLNiekto sa pokusal dostat na tvoje konto !\nAdresa: %s - %s\n",
				 user->site, user->ipsite);
			send_mail(user, user->name, text, 0);
			}
		return;
		}
	reset_user(user);
	user->login=LOGIN_NAME;
	user->pass[0]='\0';
	write_user(user, login_prompt);
	echo_on(user);
}



/*** Display better stats when logging in.  I personally use this rather than the MOTD2
     but you can use it where you want.  Gives better output than that "you last logged in"
     line tht was in connect_user
***/
void show_login_info(UR_OBJECT user)
{
	char temp[ARR_SIZE],text2[ARR_SIZE],*see[]={"~OL~FYneviditeln","~OL~FTviditeln"},*myoffon[]={"~OL~FTvyp","~OL~FRzap"};
	char *times[]={"rano","den","vecer"};
	int yes=0,cnt=0,phase,exline=0;

	set_crash();
write_user(user, ascii_tline);
if (thour>=0 && thour<10) phase=0;
else if (thour>=11 && thour<18) phase=1;
else phase=2;
sprintf(text,"Dobr%s %s, %s~RS, a witay v ~FT~OL%s~RS",
	grm_gnd(1, (phase==0)?0:1), times[phase], user->recap, reg_sysinfo[TALKERNAME]);
cnt=colour_com_count(text);
vwrite_user(user,"~CT|~RS %-*.*s ~CT|\n",76+cnt*3,76+cnt*3,text);
sprintf(text,"prixadzas k nam ~OL%s~RS",long_date(1));
cnt=colour_com_count(text);
vwrite_user(user,"~CT|~RS %-*.*s ~CT|\n",76+cnt*3,76+cnt*3,text);
write_user(user, ascii_line);
if (user->last_site[0]) {
  sprintf(temp,"%s",ctime(&user->last_login));
  temp[strlen(temp)-1]='\0';
  sprintf(text,"posledny login : ~OL%-25s~RS   tvoj level : ~OL%s~RS",temp,user_level[user->level].name);
  cnt=colour_com_count(text);
  vwrite_user(user,"~CT|~RS %-*.*s ~CT|\n",76+cnt*3,76+cnt*3,text);
  sprintf(text,"posledna sajta : ~OL%s~RS",user->last_site);
  cnt=colour_com_count(text);
  vwrite_user(user,"~CT|~RS %-*.*s ~CT|\n",76+cnt*3,76+cnt*3,text);
  exline++;
  }
if (user->level>=command_table[INVIS].level) {
  sprintf(text,"teraz si %s%s~RS",see[user->vis], grm_gnd(1, user->gender));
  if (user->level>=command_table[MONITOR].level) {
    sprintf(text2," a tvoj monitor je %s~RS",myoffon[user->monitor]);
    strcat(text,text2);
    }
  else strcat(text,"\n");
  cnt=colour_com_count(text);
  vwrite_user(user,"~CT|~RS %-*.*s ~CT|\n",76+cnt*3,76+cnt*3,text);
  exline++;
  }
else if (user->level>=command_table[MONITOR].level) {
  sprintf(text,"tvoj monitor je aktualne %s~RS",myoffon[user->monitor]);
  cnt=colour_com_count(text);
  vwrite_user(user,"~CT|~RS %-*.*s ~CT|\n",76+cnt*3,76+cnt*3,text);
  exline++;
  }
yes=0;  text2[0]='\0';  text[0]='\0';  temp[0]='\0';
if (user->ignore.all) { strcat(text2,"~FR~OLVSETKO !");  yes=1; }
if (!yes) {
  if (user->ignore.tells) { strcat(text2,"telly   ");  yes=1; }
  if (user->ignore.shouts) { strcat(text2,"shouty   ");  yes=1; }
  if (user->ignore.pics) { strcat(text2,"obr   ");  yes=1; }
  if (user->ignore.logons) { strcat(text2,"loginy   ");  yes=1; }
  if (user->ignore.wiz) { strcat(text2,"wiztelly   ");  yes=1; }
  if (user->ignore.greets) { strcat(text2,"Greets   ");  yes=1; }
  if (user->ignore.beeps) { strcat(text2,"Beeps   ");  yes=1; }
  if (user->ignore.transp) { strcat(text2,"transporty");  yes=1; }
  }
if (yes) {
  sprintf(text,"ignorujes: ~OL%s~RS",text2);
  cnt=colour_com_count(text);
  vwrite_user(user,"~CT|~RS %-*.*s ~CT|\n",76+cnt*3,76+cnt*3,text);
  exline++;
  }
if (exline) write_user(user, ascii_line);
if (user->level>=command_table[REMINDER].level) {
  cnt=has_reminder_today(user);
  sprintf(text,"Mas ~OL%d~RS pripomien%s na dnes", cnt, grm_num(2, cnt));
  cnt=colour_com_count(text);
    vwrite_user(user,"~CT|~RS %-*.*s ~CT|\n", 76+cnt*3, 76+cnt*3, text);
  cnt=remove_old_reminders(user);
  if (cnt) {
    sprintf(text, "~OL%d~RS pripomien%s zrusen%s kvoli staremu datumu", cnt, grm_num(2, cnt), grm_num(3, cnt));
  cnt=colour_com_count(text);
    vwrite_user(user,"~CT|~RS %-*.*s ~CT|\n", 76+cnt*3, 76+cnt*3, text);
    }
  write_user(user, ascii_bline);
  }
}



/*** Connect the user to the talker proper ***/
void connect_user(UR_OBJECT user)
{
	UR_OBJECT u,u2;
	RM_OBJECT rm;
	char rmname[ROOM_NAME_LEN+20],*bp,null[1];
	int cnt,newmail;

	set_crash();
null[0]='\0';
if (user->ignore.beeps) bp=NULL;  else bp="\007";

/* See if user already connected */
for(u=user_first;u!=NULL;u=u->next) {
  if (user!=u && user->type!=CLONE_TYPE && !strcmp(user->name,u->name)) {
    rm=u->room;
#ifdef NETLINKS
    /* deal with a login if the user is connected to a remote talker */
    if (u->type==REMOTE_TYPE) {
      write_user(u,"\n~FB~OLYou are pulled back through cyberspace...\n");
      sprintf(text,"REMVD %s\n",u->name);
      write_sock(u->netlink->socket,text);
      vwrite_room(rm,"%s mizne.\n",u->name);
      syspp->acounter[u->gender]--;
      syspp->acounter[3]--;
      destruct_user(u);
      reset_access(rm);
      break;
      }
#endif
    if (user->type==BOT_TYPE) close(user->socket); /* Don't want ppl logging in as the bot. */
    vwrite_user(user,"\n\nUz si pripojen%s - prepinam do starej session...\n",
 		grm_gnd(1, user->gender));
	vwrite_user(user, "Stara adresa bola %s\n", u->site);
    write_syslog(SYSLOG,1,"%s~RS  %s (%s)\n",session_swap, user->name,user->site);
    vwrite_user(u, "\n~OL~FRSwapujem tuto session na adresu ~FW%s\n\n", user->site);
    close(u->socket);
    u->socket=user->socket;
    strcpy(u->site,user->site);
    u->site_port=user->site_port;
    destruct_user(user);
    amsys->num_of_logins--;

#ifdef PUEBLO
	/* Reset pueblo status */
	if (u->pueblo!=-1) {     /* if -1 then already been detected. */
		u->pueblo=0;     /* Default to pueblo-incompatible */
		u->pblodetect=1; /* Enable pueblo to be re-detected */
		}
#endif
    if (rm==NULL) {
#ifdef NETLINKS
      sprintf(text,"ACT %s look\n",u->name);
      write_sock(u->netlink->socket,text);
#endif
      }
    else {
      look(u);
      prompt(u);
      }
    /* Reset the sockets on any clones */
    for(u2=user_first;u2!=NULL;u2=u2->next) {
      if (u2->type==CLONE_TYPE && u2->owner==user) {
	u2->socket=u->socket;  u->owner=u;
        }
      }
    return;
    }
  }
alert_friends(user, 1);
logon_flag=1;
if (!user->vis && user->level<command_table[INVIS].level) user->vis=1;
if (user->level==JAILED) {
  user->room=get_room(default_jail);
  if (user->room==NULL) user->room=room_first;
  }
else check_start_room(user);
if (user->room==room_first) rmname[0]='\0';
else if (user->room->access==PERSONAL_LOCKED || user->room->access==PERSONAL_UNLOCKED) sprintf(rmname,"~RS %s~OL",user->room->name);
else sprintf(rmname,"~RS (%s)~OL",user->room->name);
if (user->level==JAILED) {
  vwrite_room_except(NULL,user,"~OL[Being thrown into jail is:~RS %s~RS %s~RS~OL]\n",user->recap,user->desc);
  sprintf(text,"~FT%s (Site %s : Site Port : %d : Talker Port %d)\n",user->name,user->site,user->site_port,user->port);
  write_level(ARCH,1,text,user);
  }
else {
  if (user->vis) {
    if (user->level<WIZ) vwrite_room_except(NULL, user, "~OL[Entering%s is:~RS %s~RS %s~RS~OL]\n",rmname,user->recap,user->desc);
    else vwrite_room_except(NULL, user, "\07~OL[Entering%s is:~RS %s~RS %s~RS~OL]\n",rmname,user->recap,user->desc);
    sprintf(text,"~FT%s (Site %s : Site Port %d : Talker Port %d)\n",user->name,user->site,user->site_port,user->port);
    write_level(ARCH,1,text,user);
    }
  else {
    if (user->level<ARCH) write_room_except(user->room,invisenter,user);
    sprintf(text,"~OL~FY[ INVIS ]~RS ~OL[Entering%s is:~RS %s~RS %s~RS~OL]\n",rmname,user->recap,user->desc);
    write_level(WIZ,1,text,user);
    sprintf(text,"~OL~FY[ INVIS ]~RS ~FT%s (Site %s : Site Port %d : Talker Port : %d)\n",user->name,user->site,user->site_port,user->port);
    write_level(ARCH,1,text,user); 
    }
  }
logon_flag=0;
user->logons++;
if (user->level==NEW) user->t_expire=time(0)+(NEWBIE_EXPIRES*86400);
else user->t_expire=time(0)+(USER_EXPIRES*86400);
show_login_info(user);
user->last_login=time(0); /* set to now */
#ifdef PUEBLO
if (user->pueblo==-1) user->pueblo=1;
#endif
load_plugin_data(user);
look(user);
#ifdef PUEBLO
audioprompt(user, 0, 0); /* Audio greeting */
#endif
/* show how much mail the user has */
newmail=mail_sizes(user->name,1);
if (newmail)
	vwrite_user(user,"%s~FT~OL*** Mas ~RS~OL%d~FT neprecitan%s MAIL sprav%s ***\n",
		bp, newmail, grm_num(3, newmail), grm_num(1, newmail));
else if ((cnt=mail_sizes(user->name,0))) 
  vwrite_user(user,"~FT*** Mas ~RS~OL%d~RS~FT sprav%s v mail schranke ***\n",cnt, grm_num(1, cnt));
/* should they get the autopromote message? */
if (user->accreq!=-1 && amsys->auto_promote) {
  vwrite_user(user, autopromo_prompt, bp);
  }

prompt(user);
record_last_login(user->name);
write_syslog(SYSLOG,1,"%s logged in on port %d from %s:%d.\n",user->name,user->port,user->site,user->site_port);
syspp->acounter[3]++;
amsys->num_of_logins--;
syspp->tcounter[user->gender]++;
syspp->bcounter[user->gender]++;
user->tcount=++syspp->tcounter[3];
user->bcount=++syspp->bcounter[3];
syspp->acounter[user->gender]++;
if (syspp->acounter[user->gender]>syspp->mcounter[user->gender]) syspp->mcounter[user->gender]++;
if (syspp->acounter[3]>syspp->mcounter[3]) syspp->mcounter[3]++;
save_counters();
}


/******************************************************************************
 Misc and line editor functions
 *****************************************************************************/

/*** Stuff that is neither speech nor a command is dealt with here ***/
int misc_ops(UR_OBJECT user, char *inpstr)
{
	char fname[FNAME_LEN];
	int i=0;

	set_crash();
switch (user->misc_op) {
  case 1: 
    if (toupper(inpstr[0])=='Y') {
      if (amsys->rs_countdown && !amsys->rs_which) {
	if (amsys->rs_countdown>60) 
	  vwrite_room(NULL,"\n\07~OLSYSTEM: ~FR~LISHUTDOWN INITIATED, vypinam za %d minut%s, %d sekund%s!\n\n",
		  amsys->rs_countdown/60,grm_num(1, amsys->rs_countdown/60),amsys->rs_countdown%60, grm_num(1, amsys->rs_countdown%60));
	else vwrite_room(NULL,"\n\07~OLSYSTEM: ~FR~LISHUTDOWN INITIATED, vypinam za %d sekund%s!\n\n",amsys->rs_countdown,grm_num(1, amsys->rs_countdown));
#ifdef PUEBLO
	audioprompt(NULL, 6, 0);
#endif
	write_syslog(SYSLOG,1,"%s initiated a %d second%s SHUTDOWN countdown.\n",user->name,amsys->rs_countdown,PLTEXT_S(amsys->rs_countdown));
	amsys->rs_user=user;
	amsys->rs_announce=time(0);
	user->misc_op=0;  
	prompt(user);
	return 1;
        }
      talker_shutdown(user,NULL,0); 
      }
    /* This will reset any reboot countdown that was started, oh well */
    amsys->rs_countdown=0;
    amsys->rs_announce=0;
    amsys->rs_which=-1;
    amsys->rs_user=NULL;
    user->misc_op=0;  
    prompt(user);
    return 1;
    
  case 2:
    if (toupper(inpstr[0])=='E') {
      user->misc_op=0;  user->filepos=0;  user->page_file[0]='\0';
      user->status='a';
      for (i=0;i<MAX_PAGES;i++) user->pages[i]=0;
      user->pagecnt=0;
      prompt(user);
      return 1;
      }
    else if (toupper(inpstr[0])=='R') {
      if (!user->pagecnt) user->pagecnt=0;
      else user->pagecnt--;
      user->filepos=user->pages[user->pagecnt];
      }
    else if (toupper(inpstr[0])=='B') {
      if (user->pagecnt<2) user->pagecnt=0;
      else user->pagecnt=user->pagecnt-2;
      user->filepos=user->pages[user->pagecnt];
      }
    if (more(user,user->socket,user->page_file)!=1) {
      user->misc_op=0;
      user->status='a';
      user->filepos=0;
      user->page_file[0]='\0';
      for (i=0;i<MAX_PAGES;i++) user->pages[i]=0;
      user->pagecnt=0;
      prompt(user);
      }
    return 1;

  case 3: /* writing on board */
  case 4: /* Writing mail */
  case 5: /* doing profile */
    editor(user,inpstr);
    return 1;

  case 6:
    if (toupper(inpstr[0])=='Y') delete_user(user,1); 
    else {  user->misc_op=0;  prompt(user);  }
    return 1;
    
  case 7:
    if (toupper(inpstr[0])=='Y') {
      if (amsys->rs_countdown && amsys->rs_which==1) {
	if (amsys->rs_countdown>60) 
	  vwrite_room(NULL,"\n\07~OLSYSTEM: ~FY~LIREBOOT INITIATED, restartujem za %d minut%s, %d sekund%s!\n\n",
		  amsys->rs_countdown/60, grm_num(1, amsys->rs_countdown/60), amsys->rs_countdown%60, grm_num(1, amsys->rs_countdown%60));
	else vwrite_room(NULL,"\n\07~OLSYSTEM: ~FY~LIREBOOT INITIATED, restartujem za %d sekund%s!\n\n",
		amsys->rs_countdown, grm_num(1, amsys->rs_countdown));
#ifdef PUEBLO
	audioprompt(NULL, 6, 0);
#endif
	write_syslog(SYSLOG,1,"%s initiated a %d second%s REBOOT countdown.\n",user->name,amsys->rs_countdown,PLTEXT_S(amsys->rs_countdown));
	amsys->rs_user=user;
	amsys->rs_announce=time(0);
	user->misc_op=0;  
	prompt(user);
	return 1;
        }
      talker_shutdown(user,NULL,1); 
      }
    if (amsys->rs_which==1 && amsys->rs_countdown && amsys->rs_user==NULL) {
      amsys->rs_countdown=0;
      amsys->rs_announce=0;
      amsys->rs_which=-1;
      }
    user->misc_op=0;  
    prompt(user);
    return 1;

  case 8: /* Doing suggestion */
  case 9: /* Level specific mail */
    editor(user,inpstr);
    return 1;

  case 10:
    if (toupper(inpstr[0])=='E') {
      user->misc_op=0;  user->wrap_room=NULL;  prompt(user);
      user->status='a';
      }
    else rooms(user,0,1);
    return 1;
    
  case 11:
    if (toupper(inpstr[0])=='E') {
      user->misc_op=0;  user->wrap_room=NULL;  prompt(user);
      user->status='a';
      }
    else rooms(user,1,1);
    return 1;
    
  case 12:
    if (!inpstr[0]) {
      write_user(user,"Abandoning your samesite look-up.\n");
      user->misc_op=0;  user->samesite_all_store=0;  user->samesite_check_store[0]='\0';
      user->status='a';
      prompt(user);
      }
    else {
      user->misc_op=0;
      word[0][0]=toupper(word[0][0]);
      strcpy(user->samesite_check_store,word[0]);
      samesite(user,1);
      }
    return 1;
    
  case 13:
    if (!inpstr[0]) {
      write_user(user,"Abandoning your samesite look-up.\n");
      user->misc_op=0;  user->samesite_all_store=0;  user->samesite_check_store[0]='\0';
      user->status='a';
      prompt(user);
      }
    else {
      user->misc_op=0;
      strcpy(user->samesite_check_store,word[0]);
      samesite(user,2);
      }
    return 1;
    
  case 14:
    if (toupper(inpstr[0])=='E') {
      user->misc_op=0;
      user->hwrap_lev=0;
      user->hwrap_id=0;
      user->hwrap_same=0;
      user->tmp_int=0;
      user->status='a';
      prompt(user);
      }
    else help_commands_level(user,1+user->hwrap_pl);
    return 1;
    
  case 15:
    if (toupper(inpstr[0])=='E') {
      user->misc_op=0;  user->hwrap_lev=0;  user->hwrap_func=0;  user->hwrap_id=0;  user->hwrap_same=0;
      user->status='a';
      prompt(user);
      }
    else help_commands_function(user,1);
    return 1;

  case 16:
    if (toupper(inpstr[0])=='E' || more_users(user)!=1) {
      user->user_page_pos=0;  user->user_page_lev=0;  user->misc_op=0;
      user->status='a';
      prompt(user); 
      }
    return 1;

  case 17:
    if (toupper(inpstr[0])=='Y') {
      recount_users(user,1);
      }
    else { user->misc_op=0; prompt(user); }
    return 1;

  case 18:
    if (toupper(inpstr[0])=='Y') {
      sprintf(fname,"%s/%s.M", USERMAILS, user->name);
      unlink(fname);
      write_user(user,"\n~OL~FRVsetky spravy zmazane\n\n");
      }
    else write_user(user,"\nNo mail messages were deleted.\n\n");
    user->misc_op=0;
    return 1;

  case 19: /* decorating room */
    editor(user,inpstr);
    return 1;

  case 20:
    user->temp_remind.day=atoi(inpstr);
    show_reminders(user,1);
    return 1;

  case 21:
    user->temp_remind.month=atoi(inpstr);
    show_reminders(user,2);
    return 1;

  case 22:
    if (!inpstr[0]) user->temp_remind.year=tyear;
    else user->temp_remind.year=atoi(inpstr);
    show_reminders(user,3);
    return 1;

  case 23:
    strncpy(user->temp_remind.msg,inpstr,REMINDER_LEN);
    show_reminders(user,4);
    return 1;

  case 24: /* friends mail */
    editor(user,inpstr);
    return 1;

  case 101: /* restart - reinit */
    if (toupper(inpstr[0])=='Y') {
    user->misc_op=0;
    prompt(user);
      restart(user);
      }
    else {
    	user->misc_op=0;
	prompt(user);
    	}
    return 1;

	case 102: /* otazka na pouzitie set menu */
		if (toupper(inpstr[0])=='A') {
			user->misc_op=0;
			prompt(user);
			user->set_op=1;
			print_menu(user);
			no_prompt=1;
			user->ignore.all_store=user->ignore.all;
			user->ignore.all=1;
			user->status='S';
			vwrite_room_except(user->room, user, room_setup_enter, user->recap);
			}
		else {
			print_menu(user);
			user->misc_op=0;
			user->set_op=0;
			user->set_mode=SET_NONE;
			prompt(user);
			}
		return 1;
	case 103: /* help_commands_only */
		if (toupper(inpstr[0])=='E') {
			user->misc_op=0;
			user->hwrap_lev=0;
			user->hwrap_id=0;
			user->hwrap_same=0;
			user->status='a';
			prompt(user);
			}
		else help_commands_only(user, 1+user->hwrap_pl);
		return 1;
  } /* end switch */
return 0;
}


/*** The editor used for writing profiles, mail and messages on the boards ***/
void editor(UR_OBJECT user, char *inpstr)
{
	int cnt,line;
	char *ptr,*name;

	set_crash();
if (user->edit_op) {
  switch(toupper(*inpstr)) {
    case 'U':
      /* if (*user->malloc_end--!='\n') *user->malloc_end--='\n'; */
      if (user->vis) name=user->recap;  else  name=invisname;
      if (!user->vis) write_monitor(user,user->room,0);
      vwrite_room_except(user->room,user,"%s~RS dokoncil%s pisanie textu.\n",name, grm_gnd(4, user->gender));
      switch(user->misc_op) {
        case 3:  write_board(user,NULL,1);  break;
        case 4:  smail(user,NULL,1);  break;
        case 5:  enter_profile(user,1);  break;
        case 8:  suggestions(user,1);  break;
        case 9:  level_mail(user,inpstr,1);  break;
        case 19: personal_room_decorate(user,1);  break;
        case 24: friend_smail(user,NULL,1);  break;
        }
      editor_done(user);
      return;

    case 'P':
      user->edit_op=0;
      user->edit_line=1;
      user->charcnt=0;
      user->malloc_end=user->malloc_start;
      *user->malloc_start='\0';
      write_user(user,"\nZnovupisanie textu ...\n\n");
      vwrite_user(user, edit_markers, user->edit_line);
      return;
      
    case 'Z':
      write_user(user,"\nSprava zrusena.\n");
      if (user->vis) name=user->recap;
      else name=invisname;
      if (!user->vis)
      	write_monitor(user,user->room,0);
      vwrite_room_except(user->room,user,"%s~RS zrusil%s pisanie textu.\n", name, grm_gnd(4, user->gender));
      editor_done(user);  
      return;

    case 'K':
      vwrite_user(user,"\nNapisal%s si nasledujuci text ...\n\n", grm_gnd(4, user->gender));
      write_user(user,user->malloc_start);
      write_user(user, edit_prompt);
      return;
      
    default: 
      write_user(user, edit_prompt);
      return;
    } /* end switch */
  }
/* Allocate memory if user has just started editing */
if (user->malloc_start==NULL) {
  if ((user->malloc_start=(char *)malloc(MAX_LINES*81))==NULL) {
    vwrite_user(user,"%s: failed to allocate buffer memory.\n",syserror);
    write_syslog(ERRLOG,1,"Failed to allocate memory in editor().\n");
    user->misc_op=0;
    user->status='a';
    prompt(user);
    return;
    }
  clear_edit(user);
  user->ignore.all_store=user->ignore.all;
  user->ignore.all=1; /* Dont want chat mucking up the edit screen */
  user->status='E';
  user->edit_line=1;
  user->charcnt=0;
  user->editing=1;
  user->malloc_end=user->malloc_start;
  *user->malloc_start='\0';
  vwrite_user(user, "~FTMaximalne %d riad%s, koniec s '.' na samostatnom riadku.\n\n",
		MAX_LINES, grm_num(4, MAX_LINES));
  vwrite_user(user, edit_markers, 1);
  if (user->vis) name=user->recap;  else  name=invisname;
  if (!user->vis) write_monitor(user,user->room,0);
  vwrite_room_except(user->room,user,"%s~RS zacal%s pisat nejaky text ...\n",name, grm_gnd(4, user->gender));
  return;
  }
/* Check for empty line */
if (!word_count) {
  if (!user->charcnt) {
    sprintf(text,"~FG%d>~RS",user->edit_line);
    write_user(user,text);
    return;
    }
  *user->malloc_end++='\n';
  if (user->edit_line==MAX_LINES) goto END;
  vwrite_user(user,"~FG%d>~RS",++user->edit_line);
  user->charcnt=0;
  return;
  }
/* If nothing carried over and a dot is entered then end */
if (!user->charcnt && !strcmp(inpstr,".")) goto END;
line=user->edit_line;
cnt=user->charcnt;
/* loop through input and store in allocated memory */
while(*inpstr) {
  *user->malloc_end++=*inpstr++;
  if (++cnt==80) {  user->edit_line++;  cnt=0;  }
  if (user->edit_line>MAX_LINES 
      || user->malloc_end - user->malloc_start>=MAX_LINES*81) goto END;
  }
if (line!=user->edit_line) {
  ptr=(char *)(user->malloc_end-cnt);
  *user->malloc_end='\0';
  vwrite_user(user,"~FG%d>~RS%s",user->edit_line,ptr);
  user->charcnt=cnt;
  return;
  }
else {
  *user->malloc_end++='\n';
  user->charcnt=0;
  }
if (user->edit_line!=MAX_LINES) {
  vwrite_user(user,"~FG%d>~RS",++user->edit_line);
  return;
  }

/* User has finished his message , prompt for what to do now */
END:
*user->malloc_end='\0';
if (*user->malloc_start) {
  write_user(user, edit_prompt);
  user->edit_op=1;  return;
  }
write_user(user,"\nZiadny text.\n");
if (user->vis) name=user->recap;  else  name=invisname;
if (!user->vis) write_monitor(user,user->room,0);
vwrite_room_except(user->room,user,"%s~RS zrusil%s pisanie textu.\n",name, grm_gnd(4, user->gender));
editor_done(user);
}


/*** Reset some values at the end of editing ***/
void editor_done(UR_OBJECT user)
{
	set_crash();
	user->misc_op=0;
	user->edit_op=0;
	user->edit_line=0;
	free(user->malloc_start);
	user->malloc_start=NULL;
	user->malloc_end=NULL;
	user->ignore.all=user->ignore.all_store;
	user->editing=0;
	user->status='a';
	if (user->editbuff[0].buff[0]) revedit(user);
	prompt(user);
}



/******************************************************************************
 User command functions and their subsids
 *****************************************************************************/

/* control what happens when a command abbreivation is used.  Whether it needs
   to have word recount, abbreviation parsed, or whatever.
*/
int process_input_string(UR_OBJECT user, char *inpstr)
{
	set_crash();
	switch (inpstr[0]) {
		case '>': 
			if (isspace(inpstr[1])){
				strcpy(word[0],"tell");
				return 1;
				}
			if (inpstr[1]=='>') {
				if (isspace(inpstr[2])) {
					strcpy(word[0], "tellall");
					return 1;
					}
				split_com_str_num(inpstr, 2);
				strcpy(word[0], "tellall");
				return 1;
				}
			split_command_string(inpstr);
			strcpy(word[0],"tell");
			return 1;
		case ';':
			if (isspace(inpstr[1])) {
				strcpy(word[0],"emote");
				return 1;
				}
			split_command_string(inpstr);
			strcpy(word[0],"emote");
			return 1;
		case '<':
			if (isspace(inpstr[1])) {
				strcpy(word[0],"pemote");
				return 1;
				}
			split_command_string(inpstr);
			strcpy(word[0],"pemote");
			return 1;
		case '#':
			if (isspace(inpstr[1])) {
				strcpy(word[0],"semote");
				return 1;
				}
			split_command_string(inpstr);
			strcpy(word[0],"semote");
			return 1;
		case '!':
			if (isspace(inpstr[1])) {
				strcpy(word[0],"shout");
				return 1;
				}
			if (inpstr[1]=='>') {
				if (isspace(inpstr[2])) {
					strcpy(word[0], "shoutto");
					return 1;
					}
				split_com_str_num(inpstr, 2);
				strcpy(word[0], "shoutto");
				return 1;
				}
			split_command_string(inpstr);
			strcpy(word[0],"shout"); 
			return 1;
		case '-':
			if (isspace(inpstr[1])) {
				strcpy(word[0],"echo");
				return 1;
				}
			split_command_string(inpstr);
			strcpy(word[0],"echo");
			return 1;
		case '\'':
			if (isspace(inpstr[1])) {
				strcpy(word[0],"show");
				return 1;
				}
			split_command_string(inpstr);
			strcpy(word[0],"show");
			return 1;
		case '/':
			if (isspace(inpstr[1])) {
				strcpy(word[0],"sayto");
				return 1;
				}
			split_command_string(inpstr);
			strcpy(word[0],"sayto");
			return 1;
		case ',':
			if (!user->call[0]) {
				write_user(user,"Quick call nenastaveny.\n");
				return 0;
				}
			if (word_count<2) {
				vwrite_user(user, "~OLQcall nastaveny na: ~FG%s\n", user->call);
				return 0;
				}
			if (!strcmp(word[1], "-cancel")) {
				strcpy(user->call, "");
				return 0;
				}
			if (isspace(inpstr[1])) strcpy(word[0], "tell");
			else {
				split_command_string(inpstr);
				strcpy(word[0], "tell");
				}
			/* , needs to remain in inpstr for checking in the tell() function for quick call */
			return 2;
		case ':':
			if (!user->ltell[0]) {
				write_user(user,"Este ti nikto netelloval.\n");
				return 0;
				}
			if (isspace(inpstr[1])) {
				strcpy(word[0],"reply");
				return 1;
				}
			split_command_string(inpstr);
			strcpy(word[0],"reply");
			return 1;
		case '?':
			if (isspace(inpstr[1])) {
				strcpy(word[0],"help");
				return 1;
				}
			split_command_string(inpstr);
			strcpy(word[0],"help");
			return 1;
		}
	return 1;
}


/* split up command abbreviations */
void split_command_string(char *inpstr)
{
	char tmp[ARR_SIZE+2];

	set_crash();
	strcpy(tmp,&inpstr[1]);
	inpstr[1]=' ';
	strcpy(&inpstr[2],tmp);
	word_count=wordfind(inpstr);
}


/*** Deal with user input ***/
int exec_com(UR_OBJECT user, char *inpstr)
{
	int i,len;
	char *comword=NULL;
	struct command_struct *cmd;

	set_crash();
	com_num=-1;
	if (word[0][0]=='.') comword=(word[0]+1);
	else comword=word[0];
	if (!comword[0]) {
		write_user(user, unknown_command);
		return 0;
		}

/* sort out shortcuts and commands */
	switch (process_input_string(user,inpstr)) {
		case 0: return 0;
		case 1: inpstr=remove_first(inpstr);
		default: break;
		}
i=0;
len=strlen(comword);
while(command_table[i].name[0]!='*') {
  if (!strncmp(command_table[i].name,comword,len)) {  com_num=i;  break;  }
  ++i;
  }
if (!strncmp("pbloenh", comword, len)) com_num=999;
if (com_num==-1) {
	if (oss_run_plugins(user, inpstr, comword, len)) return 1;
	}
if (user->room!=NULL && com_num==-1) {
  write_user(user, unknown_command);
	return 0;
  }
record_last_command(user,com_num,strlen(inpstr));
/* You may wonder why I'm using com_num above and then scrolling through the command
   linked list again.  This is because many people like to put their commands in a
   certain order, even though they want them viewed alphabetically.  So that is they
   type .h they will get help rather than hangman.  Using the commands as they were
   originally entered (command[]) allows you to do this.  But to get the number of
   times the command has been used we still need to ++ that commands node, hence
   scrolling through the linked list.
   Also have to check the level using the command list nodes because the level of
   the commands can now be altered, therefore rendering the hard-coded levels from
   com_level[] is wrong
   Then again, you might be wondering ;)
   */

for (cmd=first_command;cmd!=NULL;cmd=cmd->next) {
  if (cmd->id==com_num) {
    if (user->room!=NULL && (has_gcom(user,cmd->id))) {
      ++cmd->count;
      break;
      }
    if (user->room!=NULL && (has_xcom(user,cmd->id))) {
      write_user(user,"Momentalne nemozes pouzit ten prikaz.\n");  return 0;
      }
    if (user->room!=NULL && (cmd->min_lev > user->level)) {
      write_user(user,"Neznamy prikaz.\n");  return 0;
      }
    ++cmd->count;
    break;
    }
  } /* end for */

/* Check if user has restriction to execute commands */
if (user->restrict[RESTRICT_EXEC]==restrict_string[RESTRICT_EXEC]) {
	if (com_num!=SAY || com_num!=QUIT || com_num!=HELP || com_num!=SUICIDE) {
		write_user(user,"~FM~OL>>>You have no right to execute that command...\n");  
		return 1;
		}
	}

#ifdef NETLINKS
/* See if user has gone across a netlink and if so then intercept certain 
   commands to be run on home site */
if (user->room==NULL) {
  switch(com_num) {
    case HOME: 
    case QUIT:
    case SUICIDE: 
    case CHARECHO:
      write_user(user,"~FY~OL*** Home execution ***\n");
      break;
    default:
      sprintf(text,"ACT %s %s %s\n",user->name,word[0],inpstr);
      write_sock(user->netlink->socket,text);
      no_prompt=1;
      return 1;
    } /* end switch */
  } /* end if */
/* Dont want certain commands executed by remote users */
if (user->type==REMOTE_TYPE) {
  switch(com_num) {
    case PASSWD  :
    case ENTPRO  :
    case ACCREQ  :
    case CONN    :
    case DISCONN :
    case SHUTDOWN:
    case REBOOT  :
    case SETAUTOPROMO:
    case DELETE  :
    case SET     :
    case PURGE   :
    case EXPIRE  :
    case LOGGING :
	case RESTART :
      write_user(user,"Sorac, vzdialeny useri nemozu pouzit tento prikaz.\n");
      return 0;
      break; /* shouldn't need this */
    default: break;
    }
  }
#endif

switch (com_num) {
  case QUIT: quit_user(user, inpstr);  break;
  case LOOK: look(user);  break;
  case SAY :
    if (word_count<2) write_user(user,"Povedat co ?\n");
    else say(user,inpstr);
    break;
  case SHOUT : shout(user,inpstr);  break;
  case TELL  : tell(user,inpstr);   break;
  case EMOTE : emote(user,inpstr);  break;
  case SEMOTE: semote(user,inpstr); break;
  case PEMOTE: pemote(user,inpstr); break;
  case ECHO  : s_echo(user,inpstr);   break;
  case GO    : go(user);  break;
  case DESC  : set_desc(user,inpstr);  break;
  case INPHRASE : 
  case OUTPHRASE: 
    set_iophrase(user,inpstr);  break; 
  case PUBCOM :
  case PRIVCOM: set_room_access(user);  break;
  case LETMEIN: letmein(user);  break;
  case INVITE : invite(user);   break;
  case TOPIC  : set_topic(user,inpstr);  break;
  case MOVE   : s_move(user);  break;
  case BCAST  : bcast(user,inpstr);  break;
  case WHO    :
  	if (!strcmp(word[1], "notify")) who(user,1);
  	else who(user,0);
  	break;
  case PEOPLE : who(user,2);  break;
  case HELP   : help(user);  break;
  case SHUTDOWN: shutdown_com(user);  break;
  case NEWS:
    switch(more(user,user->socket,NEWSFILE)) {
      case 0: write_user(user,"Neni su novinky.\n");  break;
      case 1: user->misc_op=2;
      }
    break;
  case READ  : read_board(user);  break;
  case WRITE : write_board(user,inpstr,0);  break;
  case WIPE  : wipe_board(user);  break;
  case SEARCH: search_boards(user);  break;
  case REVIEW: review(user);  break;
#ifdef NETLINKS
  case HOME  : home(user);  break;
#endif
  case STATUS: status(user);  break;
  case VER: show_version(user);  break;
  case RMAIL   : rmail(user);  break;
  case SMAIL   : smail(user,inpstr,0);  break;
  case DMAIL   : dmail(user);  break;
  case FROM    : mail_from(user);  break;
  case ENTPRO  : enter_profile(user,0);  break;
  case EXAMINE : examine(user);  break;
  case RMST    : rooms(user,1,0);  break;
#ifdef NETLINKS
  case RMSN    : rooms(user,0,0);  break;
  case NETSTAT : netstat(user);  break;
  case NETDATA : netdata(user);  break;
  case CONN    : connect_netlink(user);  break;
  case DISCONN : disconnect_netlink(user);  break;
#endif
  case PASSWD  : change_pass(user);  break;
  case KILL    : kill_user(user, inpstr);  break;
  case PROMOTE : promote(user, inpstr);  break;
  case DEMOTE  : demote(user, inpstr);  break;
  case LISTBANS: listbans(user);  break;
  case BAN     : ban(user);  break;
  case VIS     : visibility(user,1);  break;
  case INVIS   : visibility(user,0);  break;
  case SITE    : site(user);  break;
  case WAKE    : wake(user, inpstr);  break;
  case WIZSHOUT: wizshout(user,inpstr);  break;
  case MUZZLE  : muzzle(user);  break;
  case MAP: show_map(user); break;
  case LOGGING  : logging(user); break;
  case MINLOGIN : minlogin(user);  break;
  case SYSTEM   : system_details(user);  break;
  case CHARECHO : toggle_charecho(user);  break;
  case CLEARLINE: clearline(user);  break;
  case FIX      : change_room_fix(user,1);  break;
  case UNFIX    : change_room_fix(user,0);  break;
  case VIEWLOG  : viewlog(user);  break;
  case ACCREQ   : account_request(user,inpstr);  break;
  case REVCLR   : revclr(user);  break;
  case CREATE   : create_clone(user);  break;
  case DESTROY  : destroy_clone(user);  break;
  case MYCLONES : myclones(user);  break;
  case ALLCLONES: allclones(user);  break;
  case SWITCH: clone_switch(user);  break;
  case CSAY  : clone_say(user,inpstr);  break;
  case CHEAR : clone_hear(user);  break;
#ifdef NETLINKS
  case RSTAT : remote_stat(user);  break;
#endif
  case SWBAN : toggle_swearban(user);  break;
  case AFK   : afk(user,inpstr);  break;
  case CLS   : cls(user);  break;
  case SUICIDE : suicide(user);  break;
  case DELETE  : delete_user(user,0);  break;
  case REBOOT  : reboot_com(user);  break;
  case RECOUNT : check_messages(user,2);  break;
  case REVTELL : revtell(user);  break;
  case PURGE: purge_users(user);  break;
  case HISTORY: user_history(user);  break;
  case EXPIRE: user_expires(user);  break;
  case RANKS: show_ranks(user);  break;
  case WIZLIST: wiz_list(user);  break;
  case TIME: get_time(user);  break;
  case CTOPIC: clear_topic(user);  break;
  case COPYTO: copies_to(user);  break;
  case NOCOPIES: copies_to(user);  break;
  case SET: set_attributes(user,inpstr);  break;
  case MUTTER: mutter(user,inpstr);  break;
  case MKVIS: make_vis(user);  break;
  case MKINVIS: make_invis(user);  break;
  case SOS: plead(user,inpstr);  break;
  case PTELL: picture_tell(user);  break;
  case PREVIEW: preview(user);  break;
  case PICTURE: picture_all(user);  break;
  case GREET: greet(user,inpstr);  break;
  case THINKIT: think_it(user,inpstr);  break;
  case SINGIT: sing_it(user,inpstr);  break;
  case WIZEMOTE: wizemote(user,inpstr);  break;
  case SUG: suggestions(user,0);  break;
  case RSUG: suggestions(user,0);  break;
  case DSUG: delete_suggestions(user);  break;
  case LAST: show_last_login(user);  break;
  case MACROS: macros(user, inpstr);  break;
  case RULES :
    switch(more(user,user->socket,RULESFILE)) {
      case 0: write_user(user,"\nMomentalne nie su pravidla ...\n");  break;
      case 1: user->misc_op=2;
      }
    break;
  case LMAIL: level_mail(user,inpstr,0);  break;
  case ARREST: arrest(user, 0);  break;
  case VERIFY: verify_email(user);  break;
  case ADDHISTORY: manual_history(user,inpstr);  break;
  case FORWARDING: 
    switch((int)amsys->forwarding) {
      case 0: vwrite_user(user,"~FGZap%s~RS si si ~OLsmail auto-forwarding~RS.\n", grm_gnd(5, user->gender));
	amsys->forwarding=1;
	write_syslog(SYSLOG,1,"%s turned ON mail forwarding.\n",user->name);
	break;
      case 1: vwrite_user(user,"~FRVyp%s~RS si si ~OLsmail auto-forwarding~RS.\n", grm_gnd(5, user->gender));
	amsys->forwarding=0;
	write_syslog(SYSLOG,1,"%s turned OFF mail forwarding.\n",user->name);
	break;
      }
    break;
  case REVSHOUT: revshout(user);  break;
  case CLRSHOUT: clear_shouts();
    write_user(user, shout_cbuff_prompt);
    break;
  case CTELLS: clear_tells(user); 
    write_user(user,"Tvoje telly boli zmazane.\n");
    break;
  case MONITOR :
    switch(user->monitor) {
      case 0: user->monitor=1;
	write_user(user,"Odteraz monitorujes urcite veci.\n");
	break;
      case 1: user->monitor=0;
	write_user(user,"Uz nemonitorujes urcite veci.\n");
      }
    break;
  case QCALL: quick_call(user);  break;
  case ACCOUNT: create_account(user); break;
  case SAMESITE: samesite(user,0);  break;
  case BFROM: board_from(user);  break;
  case SAVEALL: force_save(user);  break;
  case JOIN: join(user);  break;
  case SHACKLE: shackle(user);  break;
  case REVAFK: revafk(user);   break;
  case CAFK: clear_afk(user);  
    write_user(user,"Tvoj AFK revbufer bol zmazany.\n");
    break;
  case REVEDIT: revedit(user);   break;
  case CEDIT: clear_edit(user);  
    write_user(user,"Tvoj EDIT revbufer bol zmazany.\n");
    break;
  case CLREMOTE: clone_emote(user,inpstr);  break;
  case LISTEN: user_listen(user);  break;
  case RETIRE : retire_user(user);  break;
  case MEMCOUNT: show_memory(user);  break;
  case CMDCOUNT: show_command_counts(user);  break;
  case RCOUNTU: recount_users(user,0);  break;
  case SETCMDLEV: set_command_level(user);  break;
  case GREPUSER: grep_users(user);  break;
  case SHOOT: shoot_user(user);  break;
  case RELOAD: reload_gun(user);  break;
  case XCOM: user_xcom(user);  break;
  case GCOM: user_gcom(user);  break;
  case SFROM: suggestions_from(user);  break;
  case SETAUTOPROMO: 
    switch(amsys->auto_promote) {
      case 0: vwrite_user(user,"~FGZap%s~RS si ~OLauto-promotes~RS pre novych userov.\n", grm_gnd(5, user->gender));
	amsys->auto_promote=1;
	write_syslog(SYSLOG,1,"%s turned ON auto-promotes.\n",user->name);
	break;
      case 1: vwrite_user(user,"~FRVyp%s~RS si ~OLauto-promotes~RS pre novych userov.\n", grm_gnd(5, user->gender));
	amsys->auto_promote=0;
	write_syslog(SYSLOG,1,"%s turned OFF auto-promotes.\n",user->name);
	break;
      }
    break;
  case SAYTO: say_to(user,inpstr);  break;
  case FRIENDS:
  	if (!strcmp(word[1], "who")) who(user, 1);
  	else friends(user);
  	break;
  case FSAY: friend_say(user,inpstr);  break;
  case FEMOTE: friend_emote(user,inpstr);  break;
  case BRING: bring(user);  break;
  case FORCE: force(user,inpstr);  break;
  case CALENDAR: show_calendar(user);  break;
  case MYROOM: personal_room(user);  break;
  case MYLOCK: personal_room_lock(user);  break;
  case VISIT: personal_room_visit(user);  break;
  case MYPAINT: personal_room_decorate(user,0);  break;
  case BEEP: s_beep(user,inpstr);  break;
  case RMADMIN: personal_room_admin(user);  break;
  case MYKEY: personal_room_key(user);  break;
  case MYBGONE: personal_room_bgone(user);  break;
  case WIZRULES:
    switch(more(user,user->socket,WIZRULESFILE)) {
      case 0: write_user(user,"\nMomentalne nie su adminske pravidla...\n");  break;
      case 1: user->misc_op=2;
      }
    break;
  case DISPLAY: display_files(user,0);  break;
  case DISPLAYADMIN: display_files(user,1);  break;
  case DUMPCMD: dump_to_file(user);  break;
  case TEMPRO : temporary_promote(user);  break;
  case MORPH  : change_user_name(user);  break;
  case FMAIL  : forward_specific_mail(user);  break;
  case REMINDER: show_reminders(user,0);  break;
  case FSMAIL: friend_smail(user,inpstr,0);  break;
  case VIEWPLUG: disp_plugin_registry(user); break;
  case PLDEBUG: oss_debugger(user); break;
  case PRIKAZY:
  	switch(user->cmd_type) {
  		case 1: help_commands_level(user, 0); break;
  		case 2: help_commands_function(user, 0); break;
  		case 3: help_commands_only(user, 0); break;
  		}
  	break;
  case TPLANE: transport_plane(user); break;
  case IGNORE: set_ignores(user); break;
  case REPLY : reply(user,inpstr);   break;
  case SHOUTTO: shoutto(user, inpstr); break;
  case TELLALL: tellall(user, inpstr); break;
  case GRMNICK: com_nick_grm(user); break;
  case AUTH:    auth_user(user); break;
  case UALARM:   set_ualarm(user); break;
  case VOTE:   volby(user); break;
  case FINGER: finger_host(user); break;
  case RLD:	reloads(user); break;
  case BANNER:  figlet(user, inpstr, 0); break;
  case TBANNER: figlet(user, inpstr, 1); break;
  case SBANNER: figlet(user, inpstr, 2); break;
  case SWEARS: swear_com(user); break;
  case MODIFY: modify(user, inpstr); break;
  case RESTRICT: restrict(user); break;
  case ABBRS: list_cmdas(user); break;
  case OPEN: system_access(user, inpstr, 1); break;
  case CLOSE: system_access(user, inpstr, 0); break;
  case BACKUP: force_backup(user); break;
  case FOLLOW: set_follow(user); break;
  case KICK: kick(user); break;
  case LEVELS:
    switch(more(user,user->socket,LEVELFILE)) {
      case 0: write_user(user,"\nMomentalne nie je info o leveloch...\n");  break;
      case 1: user->misc_op=2;
      }
    break;
  case FAQ:
    switch(more(user,user->socket,FAQFILE)) {
      case 0: write_user(user,"\nMomentalne nie su FAQ ...\n");  break;
      case 1: user->misc_op=2;
      }
    break;
  case TALKERS:
    switch(more(user,user->socket, TALKERSFILE)) {
      case 0: write_user(user,"\nMomentalne nie je zoznam talkrov ...\n");  break;
      case 1: user->misc_op=2;
      }
    break;
  case COUNTERS: show_counters(user); break;
  case HUG: hug(user, inpstr); break;
  case KISS: kiss(user, inpstr); break;
  case RESTART: restart_com(user); break;
  case MYXTERM: myxterm(user, inpstr); break;
  case ALLXTERM: allxterm(user, inpstr); break;
#ifdef DEBUG
	case TEST: test(user, inpstr); break;
#endif
#ifdef PUEBLO
	case JUKEBOX: pblo_jukebox(user); break;
#endif
	case TERMINAL: set_terminal(user, inpstr); break;
	case IDENTIFY: identify(user); break;
	case DONATE: donate_cash(user); break;
	case CASH: show_money(user); break;
	case MONEY: global_money(user); break;
	case BANK: set_bank(user, inpstr); break;
	case RESTORE: restore(user); break;
	case LYNX: lynx(user, inpstr); break;
	case MYNAME: personal_room_rename(user, inpstr); break;
	case ROOMOWNER: room_owner(user); break;
	case COLORS: switch_colors(user); break;
	case ICQPAGE: send_icqpage(user, inpstr); break;
	case PING: ping_user(user); break;
#ifdef PUEBLO
  case 999:	pblo_exec(user, inpstr); break;
#endif
  default: write_user(user,"Prikaz nespusteny.\n");
  } /* end main switch */
if (user->misc_op==2) user->status='R';
return 1;
}


/*** Shutdown the talker ***/
void talker_shutdown(UR_OBJECT user, char *str, int reboot)
{
	UR_OBJECT u,next;
#ifdef NETLINKS
	NL_OBJECT nl;
#endif
	int i;
	char *ptr;
	char *args[]={ progname,confile,NULL };

	set_crash();
if (user!=NULL) ptr=user->bw_recap;
else ptr=str;
if (reboot) {
  write_room(NULL,"\007\n~OLSYSTEM:~FY~LI Restartujem sa - fcul !!\n\n");
  write_syslog(SYSLOG,0,"*** REBOOT initiated by %s ***\n",ptr);
  }
else {
  write_room(NULL,"\007\n~OLSYSTEM:~FR~LI vypinam sa - fcul !!\n\n");
  write_syslog(SYSLOG,0,"*** SHUTDOWN initiated by %s ***\n",ptr);
  }
oss_plugin_dump();
#ifdef NETLINKS
  for(nl=nl_first;nl!=NULL;nl=nl->next) shutdown_netlink(nl);
#endif
u=user_first;
while (u) {
  next=u->next;
  /* reset ignore status - incase user was in the editor */
  if (u->editing) u->ignore.all=u->ignore.all_store;
  disconnect_user(u);
  u=next;
  }
for(i=0;i<port_total;++i) close(listen_sock[i]); 
if (reboot) {
  /* If someone has changed the binary or the config filename while this 
     prog has been running this won't work */
unlink(PIDFILE);
unlink(KILLFILE);
  execvp(progname,args);
  /* If we get this far it hasn't worked */
  write_syslog(SYSLOG,0,"*** REBOOT FAILED %s: %s ***\n\n",long_date(1),strerror(errno));
  exit(12);
  }
write_syslog(SYSLOG,0,"*** SHUTDOWN complete %s ***\n\n",long_date(1));
exit(0);
}


/*** Record speech and emotes in the room. ***/
void record(RM_OBJECT rm, char *str)
{
	set_crash();
	strncpy(rm->revbuff[rm->revline].buff, str, REVIEW_LEN);
	rm->revbuff[rm->revline].time=time(NULL);
	rm->revbuff[rm->revline].buff[REVIEW_LEN]='\n';
	rm->revbuff[rm->revline].buff[REVIEW_LEN+1]='\0';
	rm->revline=(rm->revline+1)%REVIEW_LINES;
}


/*** Records tells and pemotes sent to the user. ***/
void record_tell(UR_OBJECT user, char *str)
{
	set_crash();
	strncpy(user->revbuff[user->revline].buff,str,REVIEW_LEN);
	user->revbuff[user->revline].buff[REVIEW_LEN]='\n';
	user->revbuff[user->revline].buff[REVIEW_LEN+1]='\0';
	user->revbuff[user->revline].time=time(NULL);
	user->revline=(user->revline+1)%REVTELL_LINES;
}


/*** Records shouts and shemotes sent over the talker. ***/
void record_shout(char *str)
{
	set_crash();
	strncpy(amsys->shoutbuff[amsys->sbuffline].buff, str, REVIEW_LEN);
	amsys->shoutbuff[amsys->sbuffline].time=time(NULL);
	amsys->shoutbuff[amsys->sbuffline].buff[REVIEW_LEN]='\n';
	amsys->shoutbuff[amsys->sbuffline].buff[REVIEW_LEN+1]='\0';
	amsys->sbuffline=(amsys->sbuffline+1)%REVIEW_LINES;
}


/*** Records tells and pemotes sent to the user when afk. ***/
void record_afk(UR_OBJECT user, char *str)
{
	set_crash();
	strncpy(user->afkbuff[user->afkline].buff, str, REVIEW_LEN);
	user->afkbuff[user->afkline].time=time(NULL);
	user->afkbuff[user->afkline].buff[REVIEW_LEN]='\n';
	user->afkbuff[user->afkline].buff[REVIEW_LEN+1]='\0';
	user->afkline=(user->afkline+1)%REVTELL_LINES;
}


/*** Records tells and pemotes sent to the user when in the line editor. ***/
void record_edit(UR_OBJECT user, char *str)
{
	set_crash();
	strncpy(user->editbuff[user->editline].buff, str, REVIEW_LEN);
	user->editbuff[user->editline].time=time(NULL);
	user->editbuff[user->editline].buff[REVIEW_LEN]='\n';
	user->editbuff[user->editline].buff[REVIEW_LEN+1]='\0';
	user->editline=(user->editline+1)%REVTELL_LINES;
}


/*** Clear the review buffer in the room ***/
void clear_revbuff(RM_OBJECT rm)
{
	int c;

	set_crash();
	for (c=0;c<REVIEW_LINES;++c) {
		rm->revbuff[c].buff[0]='\0';
		rm->revbuff[c].time=0;
		}
	rm->revline=0;
}


/*** signal trapping not working, so fork twice ***/
int double_fork(void)
{
	pid_t pid;
	int dfstatus;

	set_crash();
	if (!(pid=fork())) {
		switch (fork()) {
			case  0: return 0;
			case -1: _exit(-1);
			default: _exit(0);
			}
		}
	if (pid<0||waitpid(pid,&dfstatus,0)<0) return -1;
	if (WIFEXITED(dfstatus))
		if (WEXITSTATUS(dfstatus)==0) return 1;
		else errno=WEXITSTATUS(dfstatus);
	else errno=EINTR;
	return -1;
}



/***** Message boards *****/

/* delete lines from boards or mail or suggestions, etc */
int get_wipe_parameters(UR_OBJECT user)
{
	int retval=-1;

	set_crash();
/* get delete paramters */
strtolower(word[1]);
if (!strcmp(word[1],"all")) {
  user->wipe_from=-1; user->wipe_to=-1;
  }
else if (!strcmp(word[1],"from")) {
  if (word_count<4 || strcmp(word[3],"to")) {
    write_usage(user,"%s from <#> to <#>\n", command_table[com_num].name);
    return(retval);
    }
  user->wipe_from=atoi(word[2]);
  user->wipe_to=atoi(word[4]);
  }
else if (!strcmp(word[1],"to")) {
  if (word_count<2) {
    write_usage(user,"%s to <#>\n", command_table[com_num].name);
    return(retval);
    }
  user->wipe_from=0;
  user->wipe_to=atoi(word[2]);
  }
else {
  user->wipe_from=atoi(word[1]);
  user->wipe_to=atoi(word[1]);
  }
if (user->wipe_from>user->wipe_to) {
  write_user(user,"Prve cislo musi byt vacsie ako druhe.\n");
  return(retval);
  }
retval=1;
return(retval);
}


/* removes messages from one of the board types - room boards, smail, suggestions,
  etc.  It works on the premise that every message is seperated by a newline on a
  line by itself.  And as all messages have this form - no probs :)  Just don't go
  screwing with how the messages are stored and you'll be ok :P
  from = message to start deleting at
  to = message to stop deleting at (both inclusive)
  type = 1 then board is mail, otherwise any other board
  */
int wipe_messages(char *fname, int from, int to, int type)
{
	FILE *fpi,*fpo;
	char line[ARR_SIZE];
	int rem=0,i,tmp1,tmp2;

	set_crash();
	line[0]='\0';
if (!(fpi=fopen(fname,"r"))) {
  return 0; /* return on no messages to delete */
  }
if (!(fpo=fopen(TEMPFILE, "w"))) {
  write_syslog(ERRLOG,1,"Couldn't open tempfile in wipe_message().\n");
  fclose(fpo);
  return -1; /* return on error */
  }
/* if type is mail */
if (type==1) {
  fscanf(fpi,"%d %d\r",&tmp1,&tmp2);
  fprintf(fpo,"%d %d\r",tmp1,tmp2);
  }
i=1;
while (i<from) {
  fgets(line,ARR_SIZE-1,fpi);
  while(*line!='\n') {
    if (feof(fpi)) goto SKIP_WIPE;
    fputs(line,fpo);
    fgets(line,ARR_SIZE-1,fpi);
    }
  fputs(line,fpo);
  /* message ended */
  i++;
  }
while (i<=to) {
  fgets(line,ARR_SIZE-1,fpi);
  if (feof(fpi)) goto SKIP_WIPE;
  while(*line!='\n') fgets(line,ARR_SIZE-1,fpi);
  rem++;  i++;
  }
fgets(line,ARR_SIZE-1,fpi);
while(!feof(fpi)) {
  fputs(line,fpo);
  if (*line=='\n') i++;
  fgets(line,ARR_SIZE-1,fpi);
  }
SKIP_WIPE:
fclose(fpi);
fclose(fpo);
unlink(fname);
rename(TEMPFILE, fname);
return rem;
}


/***** Bans *****/

/*** add a site without any comments to the site ban file and kick off
     all those from the same site currently logging in
***/
void auto_ban_site(char *asite)
{
	FILE *fp;
	UR_OBJECT u,next;

	set_crash();
/* Write new ban to file */
if (!(fp=fopen(SITEBAN,"a"))) {
  write_syslog(ERRLOG,1,"Couldn't open file to append in auto_ban_site().\n");
  return;
  }
fprintf(fp,"%s\n",asite);
fclose(fp);
/* disconnect the users from that same site */
u=user_first;
while(u!=NULL) {
  next=u->next;
  if (u->login && (!strcmp(asite,u->site) || !strcmp(asite,u->ipsite))) {
    write_user(u, flood_prompt);
    write_syslog(SYSLOG,1,"Line %d cleared due to port flood attempt.\n",u->socket);
    disconnect_user(u);
    }
  u=next;
  }
write_syslog(SYSLOG,1,"BANNED site/domain '%s' due to attempted flood.\n",asite);
}


/*** Ban a site from logging onto the talker ***/
void ban_site(UR_OBJECT user)
{
	FILE *fp;
	char host[81],bsite[80],check[81];

	set_crash();
gethostname(host,80);
/* check if full name matches the host's name */
if (!strcmp(word[2],host)) {
  write_user(user, this_m_ban_prompt);
  return;
  }
/* check for variations of wild card */
if (!strcmp("*",word[2])) {
  write_user(user,"Nemozes zabanovat sajtu '*'.\n");
  return;
  }
if (strstr(word[2],"**")) {
  write_user(user,"Nemozes mat ** v sajte na zabanovanie.\n");
  return;
  }
if (strstr(word[2],"?*")) {
  write_user(user,"Nemozes mat ?* v sajte na zabanovanie.\n");
  return;
  }
if (strstr(word[2],"*?")) {
  write_user(user,"Nemozes mat *? v sajte na zabanovanie.\n");
  return;
  }
/* check if, with the wild cards, the name matches host's name */
strcpy(check,word[2]);
if (check[strlen(check)-1]!='*' && check[strlen(check)-2]!='?') strcat(check,"*");
if (pattern_match(host,check)) {
  write_user(user, this_m_ban_prompt);
  return;
  }
/* See if ban already set for given site */
if ((fp=fopen(SITEBAN,"r"))) {
  fscanf(fp,"%s",bsite);
  while(!feof(fp)) {
    if (!strcmp(bsite,word[2])) {
      write_user(user,"Tato sajta/domena je uz zabanovana.\n");
      fclose(fp);  return;
      }
    fscanf(fp,"%s",bsite);
    }
  fclose(fp);
  }
/* Write new ban to file */
if (!(fp=fopen(SITEBAN,"a"))) {
  vwrite_user(user,"%s: Nemozem otvorit subor pre pridanie.\n",syserror);
  write_syslog(ERRLOG,1,"Couldn't open file to append in ban_site().\n");
  return;
  }
fprintf(fp,"%s\n",word[2]);
fclose(fp);
vwrite_user(user,"Sajta/domena '%s' je odteraz zabanovana.\n",word[2]);
write_syslog(SYSLOG,1,"%s BANNED site/domain %s.\n",user->name,word[2]);
}


/*** Ban an individual user from logging onto the talker ***/
void ban_user(UR_OBJECT user)
{
	UR_OBJECT u;
	FILE *fp;
	char name[USER_NAME_LEN+1];
	struct user_dir_struct *entry;

	set_crash();
word[2][0]=toupper(word[2][0]);
if (!strcmp(user->name,word[2])) {
  write_user(user,"Salies ? Zabanovat seba ?\n");
  return;
  }
/* See if ban already set for given user */
if ((fp=fopen(USERBAN,"r"))) {
  fscanf(fp,"%s",name);
  while(!feof(fp)) {
    if (!strcmp(name,word[2])) {
      write_user(user,"Ten user je uz zabanovany.\n");
      fclose(fp);  return;
      }
    fscanf(fp,"%s",name);
    }
  fclose(fp);
  }
/* See if already on */
if ((u=get_user(word[2]))!=NULL) {
  if (u->level>=user->level) {
    vwrite_user(user, eq_hi_lev_prompt, "zabanovat");
    return;
    }
  }
else {
  for (entry=first_dir_entry;entry!=NULL;entry=entry->next)
    if (!strcmp(entry->name,word[2])) break;
  if (entry==NULL) {
    write_user(user,nosuchuser);  return;
    }
  if (entry->level>=user->level) {
    vwrite_user(user, eq_hi_lev_prompt, "zabanovat");
    return;
    }
  }
/* Write new ban to file */
if (!(fp=fopen(USERBAN, "a"))) {
  vwrite_user(user,"%s: Nemozem otvorit subor na pridanie.\n",syserror);
  write_syslog(ERRLOG,1,"Couldn't open file to append in ban_user().\n");
  return;
  }
fprintf(fp,"%s\n",word[2]);
fclose(fp);
write_user(user,"User zabanovany.\n");
write_syslog(SYSLOG,1,"%s BANNED user %s.\n",user->name,word[2]);
sprintf(text,"User's name was ~FRbanned~RS by %s.\n",user->name);
add_history(word[2],1,text); 
if (u!=NULL) {
  write_user(u,"\n\07~FR~OL~LIYou have been banished from here and banned from returning.\n\n");
  disconnect_user(u);
  }
}


/* Ban any new accounts from a given site */
void ban_new(UR_OBJECT user)
{
	FILE *fp;
	char host[81],bsite[80],*check;

	set_crash();
gethostname(host,80);
/* check if full name matches the host's name */
if (!strcmp(word[2],host)) {
  write_user(user, this_m_ban_prompt);
  return;
  }
/* check for variations of wild card */
if (!strcmp("*",word[2])) {
  write_user(user,"Nemozes zabanovat sajtu '*'.\n");
  return;
  }
if (strstr(word[2],"**")) {
  write_user(user,"Nemozes mat ** v sajte na zabanovanie.\n");
  return;
  }
if (strstr(word[2],"?*")) {
  write_user(user,"Nemozes mat ?* v sajte na zabanovanie.\n");
  return;
  }
if (strstr(word[2],"*?")) {
  write_user(user,"Nemozes mat *? v sajte na zabanovanie.\n");
  return;
  }
/* check if, with the wild cards, the name matches host's name */
check=word[2];
if (check[strlen(check)-1]!='*') strcat(check,"*");
if (pattern_match(host,check)) {
  write_user(user, this_m_ban_prompt);
  return;
  }
/* See if ban already set for given site */
if ((fp=fopen(NEWBAN, "r"))) {
  fscanf(fp,"%s",bsite);
  while(!feof(fp)) {
    if (!strcmp(bsite,word[2])) {
      write_user(user,"New users from that site/domain have already been banned.\n");
      fclose(fp);  return;
      }
    fscanf(fp,"%s",bsite);
    }
  fclose(fp);
  }
/* Write new ban to file */
if (!(fp=fopen(NEWBAN,"a"))) {
  vwrite_user(user,"%s: Nemozem otvorit subor pre pridanie.\n",syserror);
  write_syslog(ERRLOG,1,"Couldn't open file to append in ban_new().\n");
  return;
  }
fprintf(fp,"%s\n",word[2]);
fclose(fp);
write_user(user,"Novi useri zo sajty/domeny zabanovani.\n");
write_syslog(SYSLOG,1,"%s BANNED new users from site/domain %s.\n",user->name,word[2]);
}


/*** remove a ban for a whole site ***/
void unban_site(UR_OBJECT user)
{
	FILE *infp,*outfp;
	char ubsite[80];
	int found,cnt;

	set_crash();
if (!(infp=fopen(SITEBAN,"r"))) {
  write_user(user,"Tato sajta/domena neni teraz zabanovana.\n");
  return;
  }
if (!(outfp=fopen(TEMPFILE,"w"))) {
  vwrite_user(user,"%s: Nemozem otvorit temp-fajl.\n",syserror);
  write_syslog(ERRLOG,1,"Couldn't open tempfile to write in unban_site().\n");
  fclose(infp);
  return;
  }
found=0;   cnt=0;
fscanf(infp,"%s",ubsite);
while(!feof(infp)) {
  if (strcmp(word[2],ubsite)) {  
    fprintf(outfp,"%s\n",ubsite);  cnt++;  
    }
  else found=1;
  fscanf(infp,"%s",ubsite);
  }
fclose(infp);
fclose(outfp);
if (!found) {
  write_user(user,"Tato sajta/domena neni teraz zabanovana.\n");
  unlink(TEMPFILE);
  return;
  }
if (!cnt) {
  unlink(SITEBAN);
  unlink(TEMPFILE);
  }
else rename(TEMPFILE,SITEBAN);
write_user(user,"Sajta odbanovana.\n");
write_syslog(SYSLOG,1,"%s UNBANNED site %s.\n",user->name,word[2]);
}


/*** unban a user from logging onto the talker ***/
void unban_user(UR_OBJECT user)
{
	FILE *infp,*outfp;
	char name[USER_NAME_LEN+1];
	int found,cnt;

	set_crash();
if (!(infp=fopen(USERBAN,"r"))) {
  write_user(user,"Tento user neni teraz zabanovany.\n");
  return;
  }
if (!(outfp=fopen(TEMPFILE,"w"))) {
  vwrite_user(user,"%s: Nemozem otvorit temp-fajl.\n",syserror);
  write_syslog(ERRLOG,1,"Couldn't open tempfile to write in unban_user().\n");
  fclose(infp);
  return;
  }
found=0;  cnt=0;
word[2][0]=toupper(word[2][0]);
fscanf(infp,"%s",name);
while(!feof(infp)) {
  if (strcmp(word[2],name)) {
    fprintf(outfp,"%s\n",name);  cnt++;
    }
  else found=1;
  fscanf(infp,"%s",name);
  }
fclose(infp);
fclose(outfp);
if (!found) {
  write_user(user,"Tento user neni momentalne zabanovany.\n");
  unlink(TEMPFILE);
  return;
  }
if (!cnt) {
  unlink(USERBAN);
  unlink(TEMPFILE);
  }
else rename(TEMPFILE, USERBAN);
vwrite_user(user,"User '%s' odbanovany.\n",word[2]);
write_syslog(SYSLOG,1,"%s UNBANNED user %s.\n",user->name,word[2]);
sprintf(text,"User's name was ~FGunbanned~RS by %s.\n",user->name);
add_history(word[2],0,text);
}


/* unban new accounts from a given site */
void unban_new(UR_OBJECT user)
{
	FILE *infp,*outfp;
	char ubsite[80];
	int found,cnt;

	set_crash();
if (!(infp=fopen(NEWBAN,"r"))) {
  write_user(user,"New users from that site/domain are not currently banned.\n");
  return;
  }
if (!(outfp=fopen(TEMPFILE,"w"))) {
  vwrite_user(user,"%s: Nemozem otvorit temp-fajl.\n",syserror);
  write_syslog(ERRLOG,1,"Couldn't open tempfile to write in unban_new().\n");
  fclose(infp);
  return;
  }
found=0;   cnt=0;
fscanf(infp,"%s",ubsite);
while(!feof(infp)) {
  if (strcmp(word[2],ubsite)) {  
    fprintf(outfp,"%s\n",ubsite);  cnt++;  
    }
  else found=1;
  fscanf(infp,"%s",ubsite);
  }
fclose(infp);
fclose(outfp);
if (!found) {
  write_user(user,"New users from that site/domain are not currently banned.\n");
  unlink(TEMPFILE);
  return;
  }
if (!cnt) {
  unlink(NEWBAN);
  unlink(TEMPFILE);
  }
else rename(TEMPFILE, NEWBAN);
write_user(user,"New users from site ban removed.\n");
write_syslog(SYSLOG,1,"%s UNBANNED new users from site %s.\n",user->name,word[2]);
}


/*** Everything else ;) ***/

/*** Display a short, non-colour version for the .who for those looking at it from the
     login prompt.  Thanks to Xan, Arny and Squirt for this idea (even though the code is mine ;)
***/
void login_who(UR_OBJECT user)
{
	UR_OBJECT u;
	char line[USER_NAME_LEN+10], text2[ARR_SIZE], doing[6];
	int invis, on;

	set_crash();
	write_user(user,"\n+----------------------------------------------------------------------------+\n");
	write_user(user,center_string(78,0,NULL,"Nahlaseni useri %s",long_date(1)));
	write_user(user,"+----------------------------------------------------------------------------+\n\n");

	invis=on=0;
	text[0]='\0';  text2[0]='\0';  line[0]='\0';  doing[0]='\0';

	for (u=user_first; u!=NULL; u=u->next) {
		if (u->login) continue;
		if (!u->vis) { invis++; continue; }
		if (u->afk) strcpy(doing,"<AFK> ");
		else if (u->editing) strcpy(doing,"<EDIT>");
		else strcpy(doing,"      ");
		sprintf(line,"%s %s",u->bw_recap,doing);
		sprintf(text2,"%-*s",USER_NAME_LEN+7,line);
		strcat(text,text2);
		if (!(++on%4)) {
			strcat(text,"\n");
			write_user(user,text);
			text[0]='\0';
			}
		}
	if (on%4) {
		strcat(text,"\n");
		write_user(user,text);
		}
	if (!(on+invis)) write_user(user,center_string(78,0,NULL,"Momentalne nie je nikto nalogovany\n"));
	else {
		write_user(user,"\n");
		vwrite_user(user,center_string(78,0,NULL,"%d user%s nalogovan%s, %d neviditel%s"),
			on+invis,grm_num(5, on+invis),grm_num(6, invis),invis,grm_num(6, invis));
		}
	write_user(user,"+----------------------------------------------------------------------------+\n");
}



/*** Show the list of commands, credits, and display the helpfiles for the
     given command ***/
void help(UR_OBJECT user)
{
	CM_OBJECT pcom;
	int i,ret,comnum,found;
	char fname[FNAME_LEN],text2[ARR_SIZE],cname[WORD_LEN];
	char *c;

	set_crash();
	if(user->restrict[RESTRICT_HELP]==restrict_string[RESTRICT_HELP]) {
		write_user(user,">>>You have no access to view help files!\n");
		return;
		}
	if (word_count<2) {
		main_help(user);
		return;
		}
if ((!strcmp(word[1],"prikazy")) ||(!strcmp(word[1],"commands"))) {
  switch(user->cmd_type) {
    case 1: help_commands_level(user,0);  break;
    case 2: help_commands_function(user,0);  break;
    case 3: help_commands_only(user,0); break;
    }
  return;
  }
if (!strcasecmp(word[1],"credits")) {  help_credits(user);  return;  }
/* Check for any illegal crap in searched for filename so they cannot list 
   out the /etc/passwd file for instance. */
c=word[1];
while(*c) {
  if (*c=='.' || *c++=='/') {
    write_user(user,"Sorry, there is no help on that topic.\n");
    sprintf(text,"%s[ %s requested a RESTRICTED FILENAME: %s ]\n",colors[CSYSTEM],user->name,word[1]);
    write_level(WIZ, 1, text, NULL);
    return;
    }
  }
/* due to new helpfile system below, have to check for occurance of set_X seperately */
if (strstr(word[1],"set_")) {
  /* take off the bit we need for checking */
  midcpy(word[1],cname,4,strlen(word[1]));
  i=0;
  strtolower(word[1]);
  while (set_tab[i].type[0]!='*') {
    if (!strcmp(set_tab[i].type,cname)) {
      sprintf(fname,"%s/set_%s", HELPFILES,cname);
      if (!(ret=more(user,user->socket,fname))) {
	write_user(user,"Sorac, help k tejto teme nie je.\n");
	return;
        }
      if (ret==1) user->misc_op=2;
      if (ret==2) vwrite_user(user,"~OLpre level :~RS %s a vyssi\n\n",user_level[command_table[SET].level].name);
      return;  
      }
    ++i;
    }
  /* no match found in the table */
  write_user(user,"Sorry, there is no help on that topic.\n");
  return;
  }

/* due to new helpfile system below, have to check for occurance of ign_X seperately */
	if (strstr(word[1],"ign_")) {
	  /* take off the bit we need for checking */
		midcpy(word[1],cname,4,strlen(word[1]));
		i=0;
		strtolower(word[1]);
		while (ignstr[i].type[0]!='*') {
			if (!strcmp(ignstr[i].type,cname)) {
				sprintf(fname,"%s/ign_%s", HELPFILES,cname);
				if (!(ret=more(user, user->socket, fname))) {
					write_user(user,"Sorac, help k tejto teme nie je.\n");
					return;
					}
				if (ret==1) user->misc_op=2;
				if (ret==2) {
					if (strcmp(cname, ignstr[IGN_WIZ].type)) vwrite_user(user,"~OLpre level :~RS %s a vyssi\n\n",user_level[command_table[IGNORE].level].name);
					else vwrite_user(user, "~OLpre level :~RS %s a vyssi\n\n",user_level[WIZ].name);
					}
				return;  
				}
			++i;
			}
	  /* no match found in the table */
		write_user(user,"Sorry, there is no help on that topic.\n");
		return;
		}

/* due to new helpfile system below, have to check for occurance of term_X seperately */
	if (strstr(word[1],"term_")) {
	  /* take off the bit we need for checking */
		midcpy(word[1],cname,9,strlen(word[1]));
		i=0;
		strtolower(word[1]);
		while (setterm_tab[i].type[0]!='*') {
			if (!strcmp(setterm_tab[i].type,cname)) {
				sprintf(fname,"%s/term_%s", HELPFILES, cname);
				if (!(ret=more(user, user->socket, fname))) {
					write_user(user, "Sorac, help k tejto teme nie je.\n");
					return;
					}
				if (ret==1) user->misc_op=2;
				if (ret==2) vwrite_user(user, "~OLpre level :~RS %s a vyssi\n\n",user_level[command_table[TERMINAL].level].name);
				return;  
				}
			++i;
			}
		  /* no match found in the table */
		write_user(user,"Sorry, there is no help on that topic.\n");
		return;
		}

/* do full string match first */
found=0;  i=0;  comnum=-1;
text[0]=0;
while(command_table[i].name[0]!='*') {
  if (!strcmp(command_table[i].name,word[1])) {
    comnum=i;  found=1;
    break;
    }
  ++i;
  }
/* if full string wasn't found, try to match partial string to a command */
if (!found) {
  i=0;
  while(command_table[i].name[0]!='*') {
    if (!strncmp(command_table[i].name,word[1],strlen(word[1])) && user->level>=command_table[i].level) {
      if (!found) strcat(text,"   ~OL");
      else if (!(found%8)) strcat(text,"\n   ~OL");
      strcat(text,command_table[i].name);
      strcat(text, "  ");
      comnum=i;  ++found;
      }
    ++i;
    }
  pcom=cmds_first;
  while(pcom!=NULL) {
    if (!strncmp(pcom->command,word[1],strlen(word[1])) && user->level>=pcom->req_lev) {
      if (!found) strcat(text,"   ~OL");
      else if (!(found%8)) strcat(text,"\n   ~OL");
      strcat(text,pcom->command);
      strcat(text, "  ");
      comnum=0-pcom->id-1;  ++found;
      }
    pcom=pcom->next;
    }
  if (found%8) strcat(text,"\n\n");
  else strcat(text,"\n");
  /* if more than one command matched */
  if (found>1) {
    text2[0]='\0';
    sprintf(text2,"~FR~OLMeno prikazu nie je jedinecne. '~FT%s~RS~OL~FR' zodpovedajuce polozky:\n\n",word[1]);
    write_user(user,text2);
    write_user(user,text);
    return;
    }
  /* nothing was found still? */
  if (!found) {
    write_user(user,"Sorac, taky help som nenasiel.\n");
    return;
    }
  } /* end if !found */
if (comnum>=0) {
	vwrite_user(user, "\n~OLPrikaz: ~FT%-12s       ~FWMin. level: ~FT%-10s   ~FWTyp: ~FT%s\n",
		command_table[comnum].name,
		user_level[command_table[comnum].level].name,
		command_types[command_table[comnum].function]
		);
	sprintf(fname,"%s/%s", HELPFILES,command_table[comnum].name);
	if (!(ret=more(user,user->socket,fname))) write_user(user,"\nSorry, there is no help on that topic.\n");
	}
else {
	comnum=0-comnum-1;
	for (pcom=cmds_first; pcom!=NULL; pcom=pcom->next) {
		if ((pcom->id==comnum) && (!strncmp(pcom->command, word[1], strlen(word[1])))) break;
		}
	vwrite_user(user, "\n~OLPrikaz: ~FT%-12s   ~FWMin. level: ~FT%-10s   ~FWTyp: ~FT[plugin]\n",
		pcom->command,
		user_level[pcom->req_lev].name
		);
	sprintf(fname,"%s/%s", PLHELPFILES, pcom->command);
	if (!(ret=more(user,user->socket,fname))) write_user(user,"\nSorry, there is no help on that topic.\n");
	}
if (ret==1) user->misc_op=2;
}


/*** Show the command available listed by level ***/
void help_commands_level(UR_OBJECT user, int is_wrap)
{
	CM_OBJECT plcom=cmds_first, pcom;
	int cnt,lev,total,lines=0, levtotal, i, pltot, stotal;
	char text2[ARR_SIZE],temp[20],temp1[20];
	struct command_struct *cmd=first_command;

	set_crash();
	if (is_wrap==0) {
	/* write out the header */
		write_user(user, ascii_tline);
		write_user(user,"~CT|~RS Vsetky prikazy zacinaju '.' (v ~FYkecacom~RS mode) a mozu byt skratene             ~CT|\n");
		write_user(user,"~CT|~RS '.' samotna zopakuje posledny tvoj prikaz alebo rec                          ~CT|\n");
		write_user(user, ascii_line);
		sprintf(text, help_header,user_level[user->level].name);
		sprintf(text2,"~CT|~RS %-91s ~CT|\n",text);
		write_user(user,text2);
		write_user(user, ascii_bline);
		/* set some defaults */
		cmd=first_command;
		plcom=cmds_first;
		user->hwrap_lev=JAILED;
		user->hwrap_id=first_command->id;
		user->hwrap_same=0;
		user->tmp_int=0;
		total=0;
		lines=7;
		}
	text[0]='\0';
	total=user->tmp_int;
	/* if we've gone through a screen wrap then find which node we're on */
	if (is_wrap==1) {
		cmd=first_command;
		plcom=cmds_first;
		while (cmd!=NULL) {
			if (cmd->id==user->hwrap_id) break;
			cmd=cmd->next;
			}
		}
	if (is_wrap==2) {
		cmd=first_command;
		plcom=cmds_first;
		while (plcom!=NULL) {
			if (plcom->id==user->hwrap_id && plcom->command==user->p_tmp_ch) break;
			plcom=plcom->next;
			}
		}
	/* scroll trough all the commands listing by level */
	for(lev=user->hwrap_lev;lev<=user->level; ++lev) {
		if (lev==BOT) continue;
		cnt=0;
		/* spocitanie prikazov pre dany level */
		i=0; levtotal=0;
		while(command_table[i].name[0]!='*') {
			if (command_table[i].level==lev) levtotal++;
			i++;
			}
		pcom=cmds_first;
		i=0;
		while(pcom!=NULL) {
			if (pcom->req_lev==lev) levtotal++;
			pcom=pcom->next;
			}
		/* zobrazenie hlavicky levelu */
		if ((!is_wrap) || (!user->hwrap_same)) {
			text[0]='\0';
			vwrite_user(user, help_levelname_style,
			user_level[lev].name,levtotal, user->tmp_int=(total+=levtotal));
			++lines;
			}
		else {
			sprintf(text,"    ");
			}
		user->hwrap_same=1;
		/* scroll through all commands, format and print */
		if (is_wrap!=2) {
			while(cmd!=NULL) {
				temp1[0]='\0';
				if (cmd->min_lev!=lev) {  cmd=cmd->next;  continue;  }
				sprintf(temp1,"%s %s",cmd->name,cmd->alias);
				sprintf(temp,"%-13s  ",temp1);
				strcat(text,temp);
				cnt++;
				if (cnt==5) {
					strcat(text,"\n");  
					write_user(user,text);  
					cnt=0;  ++lines;  text[0]='\0';
					}
				cmd=cmd->next;
				if (lines>=user->terminal.pager) {
					user->misc_op=14;
					user->hwrap_id=cmd->id;
					user->hwrap_lev=lev;
					user->status='R';
					write_user(user, continue2);
					return;
					cnt=0;
					}
				if (!cnt) strcat(text,"    ");
				} /* end while */
			user->hwrap_same=0;
			} /* end if is_wrap!=2 */
		while(plcom!=NULL) {
			temp1[0]='\0';
			if (plcom->req_lev!=lev) {  plcom=plcom->next;  continue;  }
			user->hwrap_same=1;
			sprintf(temp1,"%s",plcom->command);
			sprintf(temp,"%-13s  ",temp1);
			strcat(text,temp);
			cnt++;
			if (cnt==5) {  
				strcat(text,"\n");  
				write_user(user,text);  
				cnt=0;  ++lines;  text[0]='\0';
				}
			plcom=plcom->next;
			if (lines>=user->terminal.pager) {
				user->hwrap_pl=1;
				user->misc_op=14;
				user->hwrap_id=plcom->id;
				user->hwrap_lev=lev;
				user->p_tmp_ch=plcom->command;
				user->status='R';
				write_user(user, continue2);
				return;
				}
			if (!cnt) strcat(text,"    ");
			} /* end while */
		if (cnt>0 && cnt<5) {
			strcat(text,"\n");  write_user(user,text);
			++lines;  text[0]='\0';
			}
		user->hwrap_same=0;
		if (lines>=user->terminal.pager) {
			user->misc_op=14;
			user->hwrap_id=first_command->id;
			user->hwrap_lev=++lev;
			user->status='R';
			write_user(user, continue2);
			return;
			}
		cmd=first_command;
		plcom=cmds_first;
		is_wrap=1;
		} /* end for */
	/* count up total number of commands for user's level */
	total=0;
	stotal=0;
	cmd=first_command;
	while(cmd!=NULL) {
		if (cmd->min_lev>user->level) { cmd=cmd->next; continue; }
		cmd=cmd->next; ++total; ++stotal;
		}
	pltot=0;
	for(plcom=cmds_first; plcom!=NULL; plcom=plcom->next) {
		if (plcom->req_lev<=user->level) pltot++;
		stotal++;
		}
	vwrite_user(user, help_footer1, stotal, total+pltot);
	write_user(user, help_footer2);
	/* reset variables */
	user->hwrap_same=0;  user->hwrap_lev=0;  user->hwrap_id=0;  user->misc_op=0;
	user->tmp_int=0; user->status='a';
}


/*** Show the command available listed by function ***/
void help_commands_function(UR_OBJECT user, int is_wrap)
{
	CM_OBJECT plcom;
	int cnt,total,lines=0,maxfunc,len, pltot, stotal;
	char text2[ARR_SIZE],temp[20],temp1[20],*spacer=" ";
	struct command_struct *cmd;

	set_crash();
if (!is_wrap) {
  /* write out the header */
  write_user(user, ascii_tline);
  write_user(user,"~CT|~RS All commands start with a '.' (when in ~FYspeech~RS mode) and can be abbreviated   ~CT|\n");
  write_user(user,"~CT|~RS Remember, a '.' by itself will repeat your last command or speech            ~CT|\n");
  write_user(user, ascii_line);
  sprintf(text,help_header, user_level[user->level].name);
  sprintf(text2,"~CT|~RS %-91s ~CT|\n",text);
  write_user(user,text2);
  write_user(user, ascii_bline);
  /* set some defaults */
  cmd=first_command;
  user->hwrap_func=0;
  user->hwrap_lev=JAILED;
  user->hwrap_id=first_command->id;
  user->hwrap_same=0;
  lines=6;
  }
/* if we've gone through a screen wrap then find which node we're on */
if (is_wrap) {
  cmd=first_command;
  while (cmd!=NULL) {
    if (cmd->id==user->hwrap_id) break;
    cmd=cmd->next;
    }
  }

/* get how many functions there are and the length of the longest one */
maxfunc=0;  len=0;
while (command_types[maxfunc][0]!='*') {
  if (strlen(command_types[maxfunc])>len) len=strlen(command_types[maxfunc]);
  ++maxfunc;
  }
/* scroll trough all the commands listing by level */
total=0;
while (user->hwrap_func<=maxfunc) {
  cnt=0;
  /* colourize lines if need be */
  if (!is_wrap) {
    sprintf(text,"~FG~OL%*s)~RS  ~FT",len,command_types[user->hwrap_lev]);
    }
  else if (is_wrap==1 && !user->hwrap_same) {
    sprintf(text,"~FG~OL%*s)~RS  ~FT",len,command_types[user->hwrap_lev]);
    }
  else sprintf(text,"%*s   ",len,spacer);
  user->hwrap_same=1;
  /* scroll through all commands, format and print */
  while(cmd!=NULL) {
    if (cmd->function!=user->hwrap_func || cmd->min_lev>user->level) {  cmd=cmd->next;  continue;  }
    cnt++;
    temp1[0]='\0';
    sprintf(temp1,"%s %s",cmd->name,cmd->alias);
    if (cnt==5) sprintf(temp,"%s",temp1); 
    else sprintf(temp,"%-13s ",temp1);
    strcat(text,temp);
    if (cnt==5) {  
      strcat(text,"\n");
      write_user(user,text);  
      cnt=0;  ++lines;  text[0]='\0';  temp[0]='\0';
      }
    cmd=cmd->next;
    if (lines>=user->terminal.pager) {
      user->misc_op=15;
      user->hwrap_id=cmd->id;
      user->status='R';
      write_user(user, continue2);
      return;
      }
    if (!cnt) {
      sprintf(temp,"%*s   ",len,spacer);
      strcat(text,temp);
      temp[0]='\0';
      }
    } /* end while */
  user->hwrap_func++;
  user->hwrap_lev++;
  if (cnt>0 && cnt<5) {
    strcat(text,"\n");  write_user(user,text);
    ++lines;  text[0]='\0';
    }
  user->hwrap_same=0;
  if (lines>=user->terminal.pager) {
    user->misc_op=15;
    user->hwrap_id=first_command->id;
    user->status='R';
    write_user(user, continue2);
    return;
    }
  cmd=first_command;
  } /* end while */

if (is_wrap!=2) {
  /* set some defaults */
  plcom=cmds_first;
  user->hwrap_func=0;
  user->hwrap_id=cmds_first->id;
  user->hwrap_same=0;
  }
/* if we've gone through a screen wrap then find which node we're on */
if (is_wrap==2) {
  plcom=cmds_first;
  while (plcom!=NULL) {
    if (plcom->id==user->hwrap_id) break;
    plcom=plcom->next;
    }
  }

/* get how many functions there are and the length of the longest one */
maxfunc=0;  len=0;
while (command_types[maxfunc][0]!='*') {
  if (strlen(command_types[maxfunc])>len) len=strlen(command_types[maxfunc]);
  ++maxfunc;
  }
/* scroll trough all the commands listing by level */
total=0;  lines=0;  cnt=0;
  /* colourize lines if need be */
  if (is_wrap!=2) {
    sprintf(text,"~FG~OL%*s)~RS  ~FT",len,command_types[CT_PLUGINS]);
    }
  else if (is_wrap==2 && !user->hwrap_same) {
    sprintf(text,"~FG~OL%*s)~RS  ~FT",len,command_types[CT_PLUGINS]);
    }
  else sprintf(text,"%*s   ",len,spacer);
  user->hwrap_same=1;
  /* scroll through all commands, format and print */
  while(plcom!=NULL) {
    if (plcom->req_lev>user->level) {  plcom=plcom->next;  continue;  }
    cnt++;
    temp1[0]='\0';
    sprintf(temp1,"%s",plcom->command);
    if (cnt==5) sprintf(temp,"%s",temp1); 
    else sprintf(temp,"%-13s ",temp1);
    strcat(text,temp);
    if (cnt==5) {  
      strcat(text,"\n");
      write_user(user,text);  
      cnt=0;  ++lines;  text[0]='\0';  temp[0]='\0';
      }
    plcom=plcom->next;
    if (lines>=user->terminal.pager) {
      user->misc_op=21;
      user->hwrap_id=plcom->id;
      user->status='R';
      write_user(user, continue2);
      return;
      }
    if (!cnt) {
      sprintf(temp,"%*s   ",len,spacer);
      strcat(text,temp);
      temp[0]='\0';
      }
    } /* end while */
  user->hwrap_func++;
  if (cnt>0 && cnt<5) {
    strcat(text,"\n");  write_user(user,text);
    ++lines;  text[0]='\0';
    }
  user->hwrap_same=0;
  if (lines>=user->terminal.pager) {
    user->misc_op=21;
    user->hwrap_id=cmds_first->id;
    user->status='R';
    write_user(user, continue2);
    return;
    }
  plcom=cmds_first;

/* count up total number of commands for user's level */
cmd=first_command;
stotal=0;
while(cmd!=NULL) { 
  if (cmd->min_lev>user->level) { cmd=cmd->next; continue; }
  cmd=cmd->next; ++total; ++stotal;
  }
pltot=0;
for(plcom=cmds_first; plcom!=NULL; plcom=plcom->next) {
	stotal++;
	if (plcom->req_lev<=user->level) pltot++;
	}
vwrite_user(user, help_footer1, stotal, total+pltot);
write_user(user, help_footer2);
/* reset variables */
user->hwrap_same=0;  user->hwrap_func=0;  user->hwrap_lev=0;  user->hwrap_id=0;
user->misc_op=0; user->status='a';
}


/*** Show the command available ***/
void help_commands_only(UR_OBJECT user, int is_wrap)
{
	int cnt,id,total,lines=0, stotal, ptotal;
	char temp[20], text2[ARR_SIZE];
	struct command_struct *cmd=first_command;
	CM_OBJECT pcmd=cmds_first;

	set_crash();
	if (is_wrap==0) {
	/* write out the header */
		write_user(user, ascii_tline);
		write_user(user,"~CT|~RS Vsetky prikazy zacinaju '.' (v ~FYkecacom~RS mode) a mozu byt skratene             ~CT|\n");
		write_user(user,"~CT|~RS '.' samotna zopakuje posledny tvoj prikaz alebo rec                          ~CT|\n");
		write_user(user, ascii_line);
		sprintf(text, help_header,user_level[user->level].name);
		sprintf(text2,"~CT|~RS %-91s ~CT|\n",text);
		write_user(user,text2);
		write_user(user, ascii_bline);
		/* set some defaults */
		text[0]='\0';
		cmd=first_command;
		pcmd=cmds_first;
		user->hwrap_lev=JAILED;
		user->hwrap_id=first_command->id;
		user->hwrap_same=0;
		user->hwrap_pl=0;
		lines=7;
		}
	if (is_wrap==1) {
		cmd=first_command;
		pcmd=cmds_first;
		while (cmd!=NULL) {
			if (cmd->id==user->hwrap_id) break;
			cmd=cmd->next;
			}
		}
	if (is_wrap==2) {
		pcmd=cmds_first;
		while (pcmd!=NULL) {
			if (pcmd->id==user->hwrap_id) break;
			pcmd=pcmd->next;
			}
		}
	total=0;
	cnt=0;
	id=0;
	if (is_wrap!=2)
	while (cmd!=NULL) {
		if (cmd->min_lev>user->level) {
			cmd=cmd->next;
			continue;
			}
		sprintf(temp, "  %s%-11s~RS", cmd->min_lev==user->level?"~CR":"", cmd->name);
		strcat(text, temp);
		cnt++;
		if (cnt==6) {
			strcat(text, "\n");
			write_user(user, text);
			text[0]='\0';
			cnt=0;
			++lines;
			}
		cmd=cmd->next;
		if (lines>=user->terminal.pager) {
			user->misc_op=103;
			user->hwrap_id=cmd->id;
			user->hwrap_pl=0;
			user->status='R';
			write_user(user, continue2);
			return;
			}
		if (!cnt) strcat(text, "");
		}
	if (cnt) {
		strcat(text, "\n");
		write_user(user, text);
		++lines;
		text[0]='\0';
		}
	if (lines>=user->terminal.pager) {
		user->misc_op=103;
		if (is_wrap==2) user->hwrap_id=pcmd->id;
		else user->hwrap_id=cmd->id;
		user->status='R';
		write_user(user, continue2);
		return;
		}
	while (pcmd!=NULL) {
		if (pcmd->req_lev>user->level) {
			pcmd=pcmd->next;
			continue;
			}
		sprintf(temp, "  %s%-11s~RS", pcmd->req_lev==user->level?"~CR":"", pcmd->command);
		strcat(text, temp);
		cnt++;
		if (cnt==6) {
			strcat(text, "\n");
			write_user(user, text);
			text[0]='\0';
			cnt=0;
			++lines;
			}
		pcmd=pcmd->next;
		if (lines>=user->terminal.pager) {
			user->misc_op=103;
			user->hwrap_id=pcmd->id;
			user->hwrap_pl=1;
			user->status='R';
			write_user(user, continue2);
			return;
			}
		if (!cnt) strcat(text, "");
		}
	if (cnt) {
		strcat(text, "\n");
		write_user(user, text);
		++lines;
		text[0]='\0';
		}
	if (lines>=user->terminal.pager) {
		user->misc_op=103;
		if (is_wrap==2) user->hwrap_id=0;
		else user->hwrap_id=cmd->id;
		user->status='R';
		write_user(user, continue2);
		return;
		}

	/* count up total number of commands for user's level */
	total=0;
	stotal=0;
	ptotal=0;
	cmd=first_command;
	pcmd=cmds_first;
	while (cmd!=NULL) {
		if (cmd->min_lev>user->level) { cmd=cmd->next; continue; }
		cmd=cmd->next; ++total; ++stotal;
		}
	while (pcmd!=NULL) {
		if (pcmd->req_lev>user->level) { pcmd=pcmd->next; continue; }
		pcmd=pcmd->next; ++ptotal; ++stotal;
		}
	vwrite_user(user, help_footer1, stotal, total+ptotal);
	write_user(user, help_footer2);
	/* reset variables */
	user->hwrap_same=0;  user->hwrap_lev=0;  user->hwrap_id=0;
	user->misc_op=0;  user->hwrap_pl=0; user->status='a';
}


/*** Show the credits. Add your own credits here if you wish but PLEASE leave 
     my credits intact. Thanks. */
void help_credits(UR_OBJECT user)
{
	char fname[FNAME_LEN];

	set_crash();
	if (word_count<3) {
		write_user(user, "\n\nnapis ~FG.help credits lotos~RS pre credits o Lotos Pavla Hlucheho\n");
		write_user(user, "napis ~FG.help credits nuts~RS pre credits o NUTS Neila Robertsona\n");
		write_user(user, "napis ~FG.help credits amnuts~RS pre credits o AmNUTS od Andrew Collingtona\n\n");
		switch (more(user, user->socket, CREDITS)) {
			case 0: write_user(user, "Nie su informacie o autorstve :(\n");
				return;
			case 1: user->misc_op=2;
			}
		return;
		}
	/* kvoli bezpecnosti */
	if (strchr(word[2], '.') || strchr(word[2], '/')) {
		write_user(user, "Co za informacie to xces ?\n");
		return;
		}
	sprintf(fname, "%s/credits_%s", MISCFILES, word[2]);
	switch (more(user, user->socket, fname)) {
		case 0: write_user(user, "Nie su informacie o autorstve :(\n");
			return;
		case 1: user->misc_op=2;
		}
}


/*** User prompt ***/
void prompt(UR_OBJECT user)
{
	int hr,min,ign;
	int zn=0;
	char out[ARR_SIZE], hch[2];
	struct tm *tm_struct;
	time_t tm_num;

	set_crash();
	if (no_prompt) return;
#ifdef NETLINKS
	if (user->type==REMOTE_TYPE) {
		sprintf(text,"PRM %s\n",user->name);
		write_sock(user->netlink->socket,text);  
		return;
		}
#endif
	if (!user->prompt || user->misc_op || user->set_op) return;

	write_user(user, "\n");
	if (user->prompt==1 || ((user->prompt==-1) && (user->prompt_str[0]=='\0'))) {
		ign=0;
		if (user->ignore.all) ++ign;
		if (user->ignore.tells) ++ign;
		if (user->ignore.shouts) ++ign;
		if (user->ignore.pics) ++ign;
		if (user->ignore.logons) ++ign;
		if (user->ignore.wiz) ++ign;
		if (user->ignore.greets) ++ign;
		if (user->ignore.beeps) ++ign;
		if (user->ignore.transp) ++ign;
		if (user->command_mode && !user->misc_op) {
			vwrite_user(user,"~FTCOM%s%s> ",!user->vis?"+":"",ign>0?"!":"");
			return;  
			}
		hr=(int)(time(0)-user->last_login)/3600;
		min=((int)(time(0)-user->last_login)%3600)/60;
		vwrite_user(user,"~FT<%02d:%02d, %02d:%02d, %s%s%s>\n",thour,tmin,hr,min,user->bw_recap,!user->vis?"+":"",ign>0?"!":"");
		return;
		}

	out[0]='\0';
	if (user->prompt==-1) {
		for (zn=0; user->prompt_str[zn]!='\0'; zn++) {
			if (user->prompt_str[zn]=='$') {
				switch (user->prompt_str[zn+1]) {
					case 'L' :
						if ((strlen(out)+strlen(user->ltell))<ARR_SIZE)
							strcat(out, user->ltell);
						zn++;
						continue;
					case 'N' :
						if ((strlen(out)+strlen(user->name))<ARR_SIZE)
							strcat(out, user->name);
						zn++;
						continue;
					case 'R' :
						if ((strlen(out)+strlen(user->room->name))<ARR_SIZE)
							strcat(out, user->room->name);
						zn++;
						continue;
					case 'F' :
						if (user->follow[0]!='\0')
							if ((strlen(out)+strlen(user->follow))<ARR_SIZE)
								strcat(out, user->follow);
						zn++;
						continue;
					case 'S' :
						hr=(int)(time(0)-user->last_login)/3600;
						min=((int)(time(0)-user->last_login)%3600)/60;
						sprintf(text, "%d:%02d", hr, min);
						if ((strlen(out)+strlen(text))<ARR_SIZE)
							strcat(out, text);
						zn++;
						continue;
					case 'T' :
						time(&tm_num);
						tm_struct=localtime(&tm_num);
						sprintf(text, "%d:%02d",
							tm_struct->tm_hour, tm_struct->tm_min
							);
						if ((strlen(out)+strlen(text))<ARR_SIZE)
							strcat(out, text);
						zn++;
						continue;
					default :
						if ((strlen(out)+2)<ARR_SIZE) {
							out[strlen(out)-1]=user->prompt_str[zn];
							out[strlen(out)]='\0';
							}
						continue;
					}
				}
			else {
				if ((strlen(out)+1)<ARR_SIZE) {
					hch[0]=user->prompt_str[zn];
					hch[1]='\0';
					strcat(out, hch);
					}
				continue;
				}
			}
		write_user(user, out);
		write_user(user, "~RS");
		return;
		}
	return;
}

/* Set list of users that you ignore */
void show_igusers(UR_OBJECT user)
{
	int i,cnt=0;

	set_crash();
	write_user(user,"Prave ignorujes nasledujucich userov ...\n\n");
	for (i=0; i<MAX_IGNORES; ++i) {
		if (user->ignoreuser[i][0]) {
			vwrite_user(user,"   ~OL%2d~RS) %s\n",cnt+1,user->ignoreuser[i]);
			cnt++;
			}
		}
	if (!cnt) write_user(user,"   Nikoho ...\n");
	write_user(user,"\n");
}


/*** check to see if user is ignoring person with the ignoring->name ***/
int check_igusers(UR_OBJECT user, UR_OBJECT ignoring)
{
	int i;

	set_crash();
	if (user==NULL || ignoring==NULL) return -1;
	for (i=0; i<MAX_IGNORES; i++)
		if (!strcasecmp(user->ignoreuser[i],ignoring->name)) return i;
	return -1;
}


/*** Destroy all clones belonging to given user ***/
void destroy_user_clones(UR_OBJECT user)
{
	UR_OBJECT u,next;

	set_crash();
u=user_first;
while (u!=NULL) {
  next=u->next;
  if (u->type==CLONE_TYPE && u->owner==user) {
    vwrite_room(u->room,"The clone of %s~RS is engulfed in magical blue flames and vanishes.\n",u->recap);
    destruct_user(u);
    }
  u=next;
  }
}


/*** Called by go() and move() ***/
void move_user(UR_OBJECT user, RM_OBJECT rm, int teleport)
{
	RM_OBJECT old_room=user->room;

	set_crash();
	if (teleport!=2 && !has_room_access(user,rm)) {
		write_user(user,"That room is currently private, you cannot enter.\n");  
		return;
		}
	/* Reset invite room if in it */
	if (user->invite_room==rm) user->invite_room=NULL;
	if (!user->vis) {
		write_room(rm,invisenter);
		write_room_except(user->room,invisleave,user);
		goto SKIP;
		}
	if (teleport==1) {
		vwrite_room(rm,"~FT~OL%s appears in an explosion of blue magic!\n",user->bw_recap);
		vwrite_room_except(old_room,user,"~FT~OL%s chants a spell and vanishes into a magical blue vortex!\n",user->bw_recap);
		goto SKIP;
		}
	if (teleport==2) {
		write_user(user,"\n~FT~OLA giant hand grabs you and pulls you into a magical blue vortex!\n");
		vwrite_room(rm,"~FT~OL%s falls out of a magical blue vortex!\n",user->bw_recap);
#ifdef NETLINKS
		if (old_room==NULL) {
			sprintf(text,"REL %s\n",user->name);
			write_sock(user->netlink->socket,text);
			user->netlink=NULL;
			}
		else
#endif
			vwrite_room_except(old_room,user,"~FT~OLA giant hand grabs %s who is pulled into a magical blue vortex!\n",user->bw_recap);
		goto SKIP;
		}
	vwrite_room(rm,"%s~RS %s.\n",user->recap,user->in_phrase);
	vwrite_room_except(user->room,user,"%s~RS %s do %s.\n",user->recap,user->out_phrase,rm->name);

SKIP:
	user->room=rm;
	look(user);
	reset_access(old_room);
}


/*** Auto promote a user if they need to be and auto_promote is turned on ***/
void check_autopromote(UR_OBJECT user, int attrib)
{
	int cnt=0,i;

	set_crash();
if (user->level!=NEW) return; /* if user isn't NEW then don't promote */
if (user->accreq==-1) return;  /* if already been promoted then accreq should be set */

/* stop them from using same command twice */
if (BIT_TEST(user->accreq,attrib)) return;
/* check it out for stage
   1=accreq, 2=desc, 3=gender */
user->accreq=BIT_SET(user->accreq,attrib);
for (i=1;i<4;i++) if (BIT_TEST(user->accreq,i)) cnt++;
switch (cnt) {
  case 1 :
  case 2 : vwrite_user(user,"\n~OL~FY*** Urobil%s si krok cislo %d z 3 pre auto-promote ***\n\n",
			grm_gnd(4, user->gender), cnt);
           return;
  case 3 : user->accreq=-1;
           --amsys->level_count[user->level];
	   user->level++;   user->real_level=user->level;   user->unarrest=user->level;
	   user_list_level(user->name,user->level);
	   strcpy(user->date,(long_date(1)));
	   ++amsys->level_count[user->level];
	   vwrite_user(user,"\n\07~OL~FY*** Bolo na tebe vykonane autopromote na level %s ***\n\n",user_level[user->level].name);
	   sprintf(text,"Was auto-promoted to level %s.\n",user_level[user->level].name);
	   add_history(user->name,1,text);
	   write_syslog(SYSLOG,1,"%s was AUTO-PROMOTED to level %s.\n",user->name,user_level[user->level].name);
	   sprintf(text,"~OL[ AUTO-PROMOTE ]~RS %s na level %s.\n",user->name,user_level[user->level].name);
	   write_level(WIZ,1,text,NULL);
	   return;
  }
}


/* Purge users that haven't been on for the expire length of time */
int purge(int type, char *purge_site, int purge_days)
{
	UR_OBJECT u;
	struct user_dir_struct *entry;

	set_crash();
/* don't do anything if not initiated by user and auto_purge isn't on */
if (!type && !amsys->auto_purge) {
  write_syslog(SYSLOG,0,"PURGE: Auto-purge is turned off.\n");
  amsys->purge_date=time(0)+(USER_EXPIRES*86400);
  return 0; 
  }
/* write to syslog and update purge time where needed */
switch(type) {
  case 0: write_syslog(SYSLOG,1,"PURGE: Executed automatically on default.\n");
          amsys->purge_date=time(0)+(USER_EXPIRES*86400);
          break;
  case 1: write_syslog(SYSLOG,1,"PURGE: Executed manually on default.\n");
          amsys->purge_date=time(0)+(USER_EXPIRES*86400);
          break;
  case 2: write_syslog(SYSLOG,1,"PURGE: Executed manually on site matching.\n");
          write_syslog(SYSLOG,0,"PURGE: Site given was '%s'.\n",purge_site);
	  amsys->purge_date=time(0)+(USER_EXPIRES*86400);
          break;
  case 3: write_syslog(SYSLOG,1,"PURGE: Executed manually on days given.\n");
          write_syslog(SYSLOG,0,"PURGE: Days given were '%d'.\n",purge_days);
	  amsys->purge_date=time(0)+(USER_EXPIRES*86400);
          break;
  } /* end switch */
amsys->purge_count=amsys->purge_skip=amsys->users_purged=0;
entry=first_dir_entry;
while (entry!=NULL) {
  /* don't purge any logged on users */
  if (user_logged_on(entry->name)) {
    amsys->purge_skip++;
    goto PURGE_SKIP;
    }
  /* if user is not on, then free to check for purging */
  if ((u=create_user())==NULL) {
    write_syslog(ERRLOG,1,"Unable to create temporary user object in purge().\n");
    goto PURGE_SKIP;
    }
  strcpy(u->name,entry->name);
  if (!load_user_details(u)) {
    rem_user_node(u->name,-1); /* get rid of name from userlist */
    clean_files(u->name); /* just incase there are any odd files around */
    clean_retire_list(u->name); /* just incase the user is retired */
    amsys->level_count[u->level]--;
    destruct_user(u);
    destructed=0;
    goto PURGE_SKIP;
    }
  amsys->purge_count++;
  switch(type) {
    case 0: /* automatic */
    case 1: /* manual default */
      if (u->expire && (time(0)>u->t_expire)) {
        rem_user_node(u->name,-1);
	if (u->level>=WIZ) rem_wiz_node(u->name);
        clean_files(u->name);
	clean_retire_list(u->name);
        amsys->level_count[u->level]--;
        write_syslog(SYSLOG,0,"PURGE: removed user '%s'\n",u->name);
        amsys->users_purged++;
        destruct_user(u);
        destructed=0;
        goto PURGE_SKIP;
        }
      break;
    case 2: /* purge on site */
      if (u->expire && pattern_match(u->last_site,purge_site)) {
        rem_user_node(u->name,-1);
	if (u->level>=WIZ) rem_wiz_node(u->name);
        clean_files(u->name);
	clean_retire_list(u->name);
        amsys->level_count[u->level]--;
        write_syslog(SYSLOG,0,"PURGE: removed user '%s'\n",u->name);
        amsys->users_purged++;
        destruct_user(u);
        destructed=0;
        goto PURGE_SKIP;
        }
      break;
    case 3: /* given amount of days */
      if (u->expire && (u->last_login<(time(0)-(purge_days*86400)))) {
        rem_user_node(u->name,-1);
	if (u->level>=WIZ) rem_wiz_node(u->name);
        clean_files(u->name);
	clean_retire_list(u->name);
        amsys->level_count[u->level]--;
        write_syslog(SYSLOG,0,"PURGE: removed user '%s'\n",u->name);
        amsys->users_purged++;
        destruct_user(u);
        destructed=0;
        goto PURGE_SKIP;
        }
      break;
    } /* end switch */
  /* user not purged */
  destruct_user(u);
  destructed=0;
PURGE_SKIP:
  entry=entry->next;
  }
write_syslog(SYSLOG,0,"PURGE: Checked %d user%s (%d skipped), %d %s purged.\n\n",
	amsys->purge_count,PLTEXT_S(amsys->purge_count),amsys->purge_skip,amsys->users_purged,PLTEXT_WAS(amsys->users_purged));
/* just make sure that the count is all ok */
count_users();
return 1;
}


/*** Display colours to user ***/
void display_colour(UR_OBJECT user)
{
	set_crash();
	if (user->room==NULL) {
		write_user(user, "Sorrac, nemozes si zobrazit test\n");
		prompt(user);
		return;
		}
	write_user(user, "^~RS: ~OL~LI~FT~BY~RSreset\n");
	write_user(user, "^~OL: ~OLbold\n");
	write_user(user, "^~UL: ~ULunderline\n");
	write_user(user, "^~LI: ~LIblink\n");
	write_user(user, "^~RV: ~RVreverse\n");
	write_user(user, "^~FK: ~FKblack\n");
	write_user(user, "^~FR: ~FRred\n");
	write_user(user, "^~FG: ~FGgreen\n");
	write_user(user, "^~FY: ~FYyellow\n");
	write_user(user, "^~FB: ~FBblue\n");
	write_user(user, "^~FM: ~FMmagenta\n");
	write_user(user, "^~FT: ~FTtyrquiose\n");
	write_user(user, "^~FW: ~FWwhite\n");
	write_user(user, "^~BK: ~BKblack\n");
	write_user(user, "^~BR: ~BRred\n");
	write_user(user, "^~BG: ~BGgreen\n");
	write_user(user, "^~BY: ~BYyellow\n");
	write_user(user, "^~BB: ~BBblue\n");
	write_user(user, "^~BM: ~BMmagenta\n");
	write_user(user, "^~BT: ~BTtyrquiose\n");
	write_user(user, "^~BW: ~BWwhite\n");
	write_user(user, "^~BP: ~BPbeep\n");
	write_user(user, "^~CK: ~CKblack\n");
	write_user(user, "^~CR: ~CRred\n");
	write_user(user, "^~CG: ~CGgreen\n");
	write_user(user, "^~CY: ~CYyellow\n");
	write_user(user, "^~CB: ~CBblue\n");
	write_user(user, "^~CM: ~CMmagenta\n");
	write_user(user, "^~CT: ~CTtyrquiose\n");
	write_user(user, "^~CW: ~CWwhite\n");
}

/*** checks a name to see if it's in the retire list ***/
int in_retire_list(char *name)
{
	char check[USER_NAME_LEN+1];
	FILE *fp;

	set_crash();
	if (!(fp=fopen(RETIRE_LIST,"r"))) return 0;

	name[0]=toupper(name[0]);
	fscanf(fp,"%s",check);
	while(!(feof(fp))) {
		check[0]=toupper(check[0]);
		if (!strcmp(name,check)) {
			fclose(fp); return 1;
			}
		fscanf(fp,"%s",check);
		}
	fclose(fp);
	return 0;
}


/*** adds a name to the retire list ***/
void add_retire_list(char *name)
{
	FILE *fp;

	set_crash();
	if ((fp=fopen(RETIRE_LIST,"a"))) {
		fprintf(fp,"%-*s : %s\n",USER_NAME_LEN,name,long_date(1));
		fclose(fp);
		}
}


/*** removes a user from the retired list ***/
void clean_retire_list(char *name)
{
	char line[82], check[USER_NAME_LEN];
	FILE *fpi,*fpo;
	int cnt=0;

	set_crash();
	if (!(fpi=fopen(RETIRE_LIST,"r"))) return;
	if (!(fpo=fopen("templist","w"))) { fclose(fpi);  return; }

	name[0]=toupper(name[0]);
	fgets(line,82,fpi);
	sscanf(line,"%s",check);
	while(!(feof(fpi))) {
		check[0]=toupper(check[0]);
		if (strcmp(name,check)) { fprintf(fpo,"%s",line); cnt++; }
		fgets(line,82,fpi);
		sscanf(line,"%s",check);
		}
	fclose(fpi);  fclose(fpo);
	unlink(RETIRE_LIST);
	rename("templist",RETIRE_LIST);
	if (!cnt) unlink(RETIRE_LIST);
	return;
}



/*** set command bans/unbans
     banned=0/1 - 0 is unban and 1 is ban
     set=0/1 - 0 is unset and 1 is set
     ***/
int set_xgcom(UR_OBJECT user, UR_OBJECT u, int id, int banned, int set)
{
	int cnt,i;
	FILE *fp;
	char fname[FNAME_LEN];

	set_crash();
/* if banning a command with .xcom */
if (banned) {
  /* if removing the command */
  if (!set) {
    for (i=0;i<MAX_XCOMS;++i) {
      if (u->xcoms[i]==id) {
	u->xcoms[i]=-1;
	goto XGCOM_SKIP;
        }
      } /* end for */
    write_user(user,"ERROR: Nemozem odbanovat tento prikaz.\n");
    return 0;
    } /* end if */
  /* if adding the command */
  for (i=0;i<MAX_XCOMS;++i) {
    if (u->xcoms[i]==-1) {
      u->xcoms[i]=id;
      goto XGCOM_SKIP;
      }
    } /* end for */
  vwrite_user(user,"%s ma maximum zabanovanych prikazov.\n",u->name);
  return 0;
  } /* end if */

/* if giving a command with .gcom */
/* if removing the command */
if (!set) {
  for (i=0;i<MAX_GCOMS;++i) {
    if (u->gcoms[i]==id) {
      u->gcoms[i]=-1;
      goto XGCOM_SKIP;
      }
    } /* end for */
  write_user(user,"ERROR: Nemozem odbanovat tento prikaz.\n");
  return 0;
  } /* end if */
/* if adding the command */
for (i=0;i<MAX_GCOMS;++i) {
  if (u->gcoms[i]==-1) {
    u->gcoms[i]=id;
    goto XGCOM_SKIP;
    }
  } /* end for */
vwrite_user(user,"%s ma maximalny pocet pridanych prikazov.\n",u->name);
return 0;
/* write out the commands to a file */
XGCOM_SKIP:
sprintf(fname,"%s/%s.C", USERCOMMANDS,u->name);
if (!(fp=fopen(fname,"w"))) {
  write_user(user,"ERROR: Unable to open the command list file.\n");
  write_syslog(ERRLOG,1,"Unable to open %s's command list in set_xgcom().\n",u->name);
  return 0;
  }
cnt=0;
for (i=0;i<MAX_XCOMS;++i) {
  if (u->xcoms[i]==-1) continue;
  fprintf(fp,"0 %d\n",u->xcoms[i]);
  cnt++;
  }
for (i=0;i<MAX_GCOMS;++i) {
  if (u->gcoms[i]==-1) continue;
  fprintf(fp,"1 %d\n",u->gcoms[i]);
  cnt++;
  }
fclose(fp);
if (!cnt) unlink(fname);
return 1;
}


/*** read any banned commands that a user may have ***/
int get_xgcoms(UR_OBJECT user)
{
	int i,type,tmp;
	FILE *fp;
	char fname[FNAME_LEN];

	set_crash();
	sprintf(fname,"%s/%s.C", USERCOMMANDS,user->name);
	if (!(fp=fopen(fname,"r"))) return 0;
	i=0;
	fscanf(fp,"%d %d",&type,&tmp);
	while (!feof(fp)) {
		if (!type) user->xcoms[i]=tmp;
		else user->gcoms[i]=tmp;
		i++;
		fscanf(fp,"%d %d",&type,&tmp);
		}
	fclose(fp);
	return 1;
}



/*****************************************************************************
 Friend commands and their subsids
 *****************************************************************************/

/* Determine whether user has u listed on their friends list */
int user_is_friend(UR_OBJECT user, UR_OBJECT u)
{
	int i;

	set_crash();
	for (i=0;i<MAX_FRIENDS;++i)
		if (!strcmp(user->friend[i],u->name))
			return 1;
	return 0;
}


/* Alert anyone logged on who has user in their friends 
   list that the user has just loged on */ 
void alert_friends(UR_OBJECT user, int mode)
{
	UR_OBJECT u;

	set_crash();
	for (u=user_first;u!=NULL;u=u->next) {
		if (!u->alert || u->login) continue;
		if ((user_is_friend(u,user)) && user->vis) {
			if (mode)
				vwrite_user(u,"\n\07~FG~OL~LIHEY!~RS~OL~FG  tvoj%s kamos%s ~RS%s~FG~OL sa prilogoval%s\n",
					grm_gnd(3, user->gender), grm_gnd(2, user->gender), user->recap, grm_gnd(4, user->gender));
			else
				vwrite_user(u,"\n\07~FR~OL~LIHEY!~RS~OL~FR  tvoj%s kamos%s ~RS%s~FR~OL sa odlogoval%s\n",
					grm_gnd(3, user->gender), grm_gnd(2, user->gender), user->recap, grm_gnd(4, user->gender));
			}
		}
}


/* Read from the friends file into the user structure */
void get_friends(UR_OBJECT user)
{
	char fname[FNAME_LEN],name[USER_NAME_LEN];
	FILE *fp;
	int i;

	set_crash();
	sprintf(fname,"%s/%s.F", USERFRIENDS,user->name);
	if (!(fp=fopen(fname,"r"))) return;
	i=0;
	fscanf(fp,"%s",name);
	while(!feof(fp)) {
		strcpy(user->friend[i],name);
		i++;
		fscanf(fp,"%s",name);
		}
	fclose(fp);
}


/*****************************************************************************
              based upon scalar date routines by Ray Gardner
                and CAL - a calendar for DOS by Bob Stout
 *****************************************************************************/

/* determine if year is a leap year */
int is_leap(unsigned yr)
{
	set_crash();
	return yr%400==0 || (yr%4==0 && yr%100!=0);
}


/* convert months to days */
unsigned months_to_days(unsigned mn)
{
	set_crash();
	return (mn*3057-3007)/100;
}


/* convert years to days */
long years_to_days(unsigned yr)
{
	set_crash();
	return yr*365L+yr/4-yr/100+yr/400;
}


/* convert a given date (y/m/d) to a scalar */
long ymd_to_scalar(unsigned yr, unsigned mo, unsigned dy)
{
	long scalar;

	set_crash();
	scalar=dy+months_to_days(mo);
	/* adjust if past February */
	if (mo>2) scalar-=is_leap(yr)?1:2;
	yr--;
	scalar+=years_to_days(yr);
	return scalar;
}


/* converts a scalar date to y/m/d */
void scalar_to_ymd(long scalar, unsigned *yr, unsigned *mo, unsigned *dy)
{
	unsigned n;

	set_crash();
	/* 146097 == years_to_days(400) */
	for (n=(unsigned)((scalar*400L)/146097);years_to_days(n)<scalar;) n++;
	*yr=n;
	n=(unsigned)(scalar-years_to_days(n-1));
	/* adjust if past February */
	if (n>59) {                       
		n+=2;
		if (is_leap(*yr)) n-=n>62?1:2;
		}
	/* inverse of months_to_days() */
	*mo=(n*100+3007)/3057;
	*dy=n-months_to_days(*mo);
}


/* determine if the y/m/d given is todays date */
int is_ymd_today(unsigned yr, unsigned mo, unsigned dy)
{
	set_crash();
	if (((int)yr==(int)tyear)
	    && ((int)mo==(int)tmonth+1)
	    && ((int)dy==(int)tmday))
		return 1;
	  return 0;
}


/*** check to see if a user has a reminder for a given date ***/
int has_reminder(UR_OBJECT user, int dd, int mm, int yy)
{
	int i,cnt;

	set_crash();
	for (i=0,cnt=0;i<MAX_REMINDERS;i++)
		if (user->reminder[i].day==dd && user->reminder[i].month==mm && user->reminder[i].year==yy) cnt++;
	return cnt;
}


/*** check to see if a user has a reminder for today ***/
int has_reminder_today(UR_OBJECT user)
{
	int i,d=tmday,m=tmonth+1,y=tyear,cnt;

	set_crash();
	for (i=0,cnt=0;i<MAX_REMINDERS;i++)
		if (user->reminder[i].day==d
		    && user->reminder[i].month==m
		    && user->reminder[i].year==y)
			cnt++;
	return cnt;
}


/*** cleans any reminders that have expired - no point keeping them! ***/
int remove_old_reminders(UR_OBJECT user)
{
	int d,m,y,tdate,odate,cnt_total,i;

	set_crash();
	d=tmday;
	m=tmonth+1;
	y=tyear;
	tdate=(int)ymd_to_scalar(y,m,d);
	cnt_total=0;
	for (i=0;i<MAX_REMINDERS;i++) {
		if (!user->reminder[i].msg[0]) continue;
		odate=(int)ymd_to_scalar(user->reminder[i].year,user->reminder[i].month,user->reminder[i].day);
		if (odate<tdate) {
			user->reminder[i].day=0;
			user->reminder[i].month=0;
			user->reminder[i].year=0;
			user->reminder[i].msg[0]='\0';
			cnt_total++;
			}
		}
	if (cnt_total) write_user_reminders(user);
	return cnt_total;
}



/*** read in the user's reminder file ***/
int read_user_reminders(UR_OBJECT user)
{
	FILE *fp;
	char fname[FNAME_LEN],line[REMINDER_LEN+1];
	int ln=0,i=0;

	set_crash();
	sprintf(fname,"%s/%s.REM", USERREMINDERS,user->name);
	if (!(fp=fopen(fname,"r"))) return 0;
	fscanf(fp,"%d %d %d %d\n",
		&user->reminder[i].day,&user->reminder[i].month,&user->reminder[i].year,&user->reminder[i].alert);
	ln=1;
	while (!(feof(fp))) {
		if (i>MAX_REMINDERS) break;
		if (ln) {
			fgets(line,REMINDER_LEN,fp);
			line[strlen(line)-1]=0;
			strcpy(user->reminder[i].msg,line);
			i++;
			ln=0;
			}
		else {
			fscanf(fp,"%d %d %d %d\n",
				&user->reminder[i].day,&user->reminder[i].month,&user->reminder[i].year,&user->reminder[i].alert);
			ln=1;
			}
		}
	fclose(fp);
	return i;
}


/*** store a user's reminders to their .R file ***/
int write_user_reminders(UR_OBJECT user)
{
	FILE *fp;
	char fname[FNAME_LEN];
	int i,cnt;

	set_crash();
	sprintf(fname,"%s/%s.REM", USERREMINDERS,user->name);
	if (!(fp=fopen(fname,"w"))) {
		write_syslog(ERRLOG,1,"Could not open %s reminder file for writing in write_reminders()\n",user->name);
		return 0;
		}
	cnt=0;
	for (i=0;i<MAX_REMINDERS;i++) {
		if (!user->reminder[i].msg[0]) continue;
		fprintf(fp,"%d %d %d 0\n",
			user->reminder[i].day,user->reminder[i].month,user->reminder[i].year);
		fputs(user->reminder[i].msg,fp);
		fprintf(fp,"\n");
		++cnt;
		}
	fclose(fp);
	if (!cnt) unlink(fname);
	return 1;
}



/*****************************************************************************/

/* save and load personal room information for the user of name given.
   if store=0 then read info from file else store.
   */
int personal_room_store(char *name, int store, RM_OBJECT rm) {
	FILE *fp;
	char fname[FNAME_LEN],line[TOPIC_LEN+1],c;
	int i;

if (rm==NULL) return 0;
/* load the info */
if (!store) {
  strtolower(name);
  name[0]=toupper(name[0]);
  sprintf(fname,"%s/%s.R", USERROOMS,name);
  if (!(fp=fopen(fname,"r"))) {
    /* if can't open the file then just put in default attributes */
    rm->access=PERSONAL_UNLOCKED;
    strcpy(rm->desc, default_personal_room_desc);
    strcpy(rm->topic, default_personal_room_topic);
	strcpy(rm->real_name, name);
    return 0;
    }
  fscanf(fp,"%d\n",&rm->access);
  fgets(line,TOPIC_LEN+1,fp);
  line[strlen(line)-1]='\0';
  if (!strcmp(line,"#UNSET")) rm->topic[0]='\0';
  else strcpy(rm->topic,line);
  fgets(line,PERSONAL_ROOMNAME_LEN+1,fp);
  line[strlen(line)-1]='\0';
  strcpy(rm->real_name,line);
  i=0;
  c=getc(fp);
  while (!feof(fp)) {
    if (i==ROOM_DESC_LEN) {
      write_syslog(ERRLOG,1,"Description too long when reloading for room %s.\n",rm->name);
      break;
      } /* end if */
    rm->desc[i]=c;
    c=getc(fp);
    ++i;
    } /* end while */
  rm->desc[i]='\0';
  fclose(fp);
  rm->link[0]=room_first;
  return 1;
  }
/* save info */
strtolower(name);
name[0]=toupper(name[0]);
sprintf(fname,"%s/%s.R", USERROOMS,name);
if (!(fp=fopen(fname,"w"))) return 0;
fprintf(fp,"%d\n",rm->access);
(!rm->topic[0]) ? fprintf(fp,"#UNSET\n") : fprintf(fp,"%s\n",rm->topic);
fprintf(fp,"%s\n",rm->real_name);
i=0;
while (i!=ROOM_DESC_LEN) {
  if (rm->desc[i]=='\0') break;
  putc(rm->desc[i++],fp);
  }
fclose(fp);
return 1;
}


/*** adds a name to the user's personal room key list ***/
int personal_key_add(UR_OBJECT user,char *name)
{
	FILE *fp;
	char fname[FNAME_LEN];

	set_crash();
	sprintf(fname,"%s/%s.K", USERROOMS,user->name);
	if ((fp=fopen(fname,"a"))) {
		fprintf(fp,"%s\n",name);
		fclose(fp);
		return 1;
		}
	return 0;
}


/*** remove a name from the user's personal room key list ***/
int personal_key_remove(UR_OBJECT user,char *name)
{
	char filename[FNAME_LEN], fname[FNAME_LEN], line[USER_NAME_LEN+2];
	FILE *fpi,*fpo;
	int cnt=0;

	set_crash();
	sprintf(filename,"%s/%s.K", USERROOMS,user->name);
	if (!(fpi=fopen(filename,"r"))) return 0;
	sprintf(fname, "%s/tempkeylist", TEMPFILES);
	if (!(fpo=fopen(fname, "w"))) {
		fclose(fpi);
		return 0;
		}

	fscanf(fpi,"%s",line);
	while(!(feof(fpi))) {
		if (strcmp(name,line)) {
			fprintf(fpo,"%s\n",line);
			cnt++;
			}
		fscanf(fpi,"%s",line);
		}
	fclose(fpi);
	fclose(fpo);
	unlink(filename);
	rename(fname, filename);
	if (!cnt) unlink(filename);
	return 1;
}


#endif /* __MAIN_C__ */