/*
* Copyright (C) 1995-1997 Christopher D. Granz
*
* This header may not be removed.
*
* Refer to the file "License" included in this package for further
* information and before using any of the following.
*/
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <dirent.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "sapphire.h"
/*
* Functions
*/
void process_shell_cmd( TERM_DATA *pTerm, char *pCommand )
{
char cCommand[MAX_INPUT];
int i;
if ( next_char( pCommand ) == '\0' )
return;
pCommand = one_arg( pCommand, cCommand );
for ( i = 0; scShellCmdTable[i].pName[0] != '\0'; i++ )
{
if ( strcmp( cCommand, scShellCmdTable[i].pName ) == 0 )
{
( *scShellCmdTable[i].pCmdFunc ) ( pTerm, pCommand );
return;
}
}
#if 0
{
char **argv;
char *env[] = { NULL };
pid_t pPid;
int iStdin[2], iStdout[2], iStderr[2];
pipe( iStdin );
pipe( iStdout );
pipe( iStderr );
if ( ( pPid = fork( ) ) == 0 )
{
dup2( iStdin[0], STDIN_FILENO );
dup2( iStdout[1], STDOUT_FILENO );
dup2( iStderr[1], STDERR_FILENO );
argv = alloc_mem( ( sizeof( char * ) * 2 ) );
argv[0] = str_dup( cCommand );
for ( i = 1; pCommand[0] != '\0'; i++ )
{
argv = realloc_mem( argv, ( sizeof( char * ) * ( i + 2 ) ) );
pCommand = one_arg( pCommand, cCommand );
argv[i] = str_dup( cCommand );
}
argv[i] = NULL;
execve( argv[0], argv, env );
printf( "execve() failed for `%s': %s.\n", argv[0],
strerror( errno ) );
exit( 1 );
}
else
{
pTerm->iConState = CON_RUNNING_CHILD;
pTerm->iConStateOld = CON_SYSTEM_SHELL;
pTerm->pChildP = new_child( pPid, iStdin, iStdout, iStderr,
cCommand );
pTerm->pInBuffer[0] = '\0';
flush_buffer( pTerm );
return;
}
}
#endif
write_string_buffer( pTerm, "Command not found.\n\r\n\r" );
}
/*
* Command to enter the development shell.
*/
void cmd_shell( CHAR_DATA *pChar, char *pArgument )
{
TERM_DATA *pTerm;
char cBuf[256];
if ( pChar->pTerm == NULL )
return;
if ( IS_NPC( pChar ) )
{
send_string( pChar,
"Why would NPCs need to use the development shell?\n\r" );
return;
}
send_game_message( "~c has left this world.", MESSAGE_DEST_ROOM, TRUE,
pChar, NULL, pChar->pInRoom, TRUE, NUMBER_POSITION_RESTING, pChar );
char_from_room( pChar );
write_string_buffer( pChar->pTerm, make_ansi_code(
ANSI_CODEREF_EF_CSCREEN, NULL, NULL, pChar->pTerm ) );
send_string( pChar,
"\n\rType `exit' to leave the development shell.\n\r\n\r" );
for ( pTerm = pTermList; pTerm != NULL; pTerm = pTerm->pNext )
{
if ( pTerm->iConState == CON_SYSTEM_SHELL )
{
sprintf( cBuf,
"\n\r%s@%s has entered the development shell.\n\r\n\r",
pChar->pPCData->sName, pChar->pTerm->pHostname );
write_string_buffer( pTerm, cBuf );
}
}
pChar->pTerm->iConState = CON_SYSTEM_SHELL;
}
/*
* Returns TRUE is pPath is a valid path.
*/
static bool legal_path( TERM_DATA *pTerm, char *pPath )
{
char cBuf[512];
char *pBuf = pTerm->pCurrentDir;
int iCount = 0;
int i;
while ( ( pBuf = strchr( pBuf, '/' ) ) != NULL )
{
pBuf++;
iCount++;
}
while ( pPath[0] != '\0' )
{
if ( ( pBuf = strchr( pPath, '/' ) ) == NULL )
{
strcpy( cBuf, pPath );
pPath = EMPTY_STRING;
}
else
{
strncpy( cBuf, pPath, ( i = ( pBuf - pPath ) ) );
cBuf[i] = '\0';
pPath = ( pBuf + 1 );
}
if ( strcmp( cBuf, ".." ) == 0 )
{
iCount--;
if ( iCount < 0 )
return ( FALSE );
}
else if ( cBuf[0] != '\0' && strcmp( cBuf, "." ) != 0 )
iCount++;
}
return ( TRUE );
}
/*
* Removes multiple slashes, `.' and `dir/..' from a path string.
*/
static char *clean_up_path( char *pPath )
{
char *pOutBuf = new_buffer( );
char *pBuf = pPath;
char *pBuf2;
char cBuf[MAX_STRING];
int iCount = 0;
pOutBuf[0] = '\0';
if ( *pBuf == '/' )
strcpy( pOutBuf, "/" );
while ( *pBuf != '\0' )
{
while ( *pBuf == '/' )
pBuf++;
pBuf = edit_str( pBuf, cBuf, ' ', "/" );
if ( strcmp( cBuf, ".." ) == 0 )
{
if ( iCount > 0 )
{
iCount--;
pOutBuf[strlen( pOutBuf ) - 1] = '\0';
if ( ( pBuf2 = strrchr( pOutBuf, '/' ) ) != NULL )
*++pBuf2 = '\0';
else
{
if ( *pOutBuf == '/' )
pOutBuf[1] = '\0';
else
*pOutBuf = '\0';
}
continue;
}
else
strcat( pOutBuf, ".." );
}
else if ( strcmp( cBuf, "." ) == 0 )
continue;
else
{
iCount++;
strcat( pOutBuf, cBuf );
}
if ( *pBuf == '/' )
strcat( pOutBuf, "/" );
}
return ( pOutBuf );
}
/*
* Command to exit the development shell.
*/
void shell_cmd_exit( TERM_DATA *pTerm, char *pArgument )
{
TERM_DATA *pTerm2;
char cBuf[256];
pTerm->iConState = CON_PLAYING;
if ( pTerm->pChar != NULL )
{
for ( pTerm2 = pTermList; pTerm2 != NULL; pTerm2 = pTerm2->pNext )
{
if ( pTerm2->iConState == CON_SYSTEM_SHELL )
{
sprintf( cBuf,
"\n\r%s@%s has left the development shell.\n\r\n\r",
pTerm->pChar->pPCData->sName, pTerm->pHostname );
write_string_buffer( pTerm2, cBuf );
}
}
char_to_room( pTerm->pChar, uDefaultRoom.pRoom );
send_game_message( "~h appears out of nothingness.",
MESSAGE_DEST_ROOM, TRUE, pTerm->pChar, NULL,
pTerm->pChar->pInRoom, TRUE, NUMBER_POSITION_RESTING,
pTerm->pChar );
write_string_buffer( pTerm, make_ansi_code(
ANSI_CODEREF_EF_CSCREEN, NULL, NULL, pTerm ) );
}
}
/*
* Changes the user's directory.
*/
void shell_cmd_cd( TERM_DATA *pTerm, char *pArgument )
{
DIR *pDir;
char cBuf[1024];
char cArg[MAX_INPUT];
char *pArg = cArg;
pArgument = one_arg( pArgument, cArg );
strcpy( cArg, clean_up_path( cArg ) );
if ( ( strlen( pShellDir ) + strlen( pTerm->pCurrentDir )
+ strlen( cArg ) + 2 ) > 1024 )
{
write_string_buffer( pTerm, "Path too long.\n\r\n\r" );
str_free( pTerm->pCurrentDir );
pTerm->pCurrentDir = EMPTY_STRING;
return;
}
strcpy( cBuf, pShellDir );
if ( cArg[0] == '/' )
pArg++;
else
strcat( cBuf, pTerm->pCurrentDir );
if ( cArg[0] != '\0' )
{
if ( legal_path( pTerm, cArg ) != TRUE )
{
write_string_buffer( pTerm, "Illegal path.\n\r\n\r" );
return;
}
strcat( cBuf, pArg );
}
if ( ( pDir = opendir( cBuf ) ) == NULL )
{
write_string_buffer( pTerm, "No such directory.\n\r\n\r" );
return;
}
if ( readdir( pDir ) == NULL )
{
closedir( pDir );
write_string_buffer( pTerm, "Not a directory.\n\r\n\r" );
return;
}
closedir( pDir );
if ( pArg[0] == '\0' )
cBuf[0] = '\0';
else
{
if ( cArg[0] != '/' )
{
strcpy( cBuf, pTerm->pCurrentDir );
strcat( cBuf, pArg );
}
else
strcpy( cBuf, pArg );
if ( cBuf[strlen( cBuf ) - 1] != '/' )
strcat( cBuf, "/" );
}
str_free( pTerm->pCurrentDir );
pTerm->pCurrentDir = str_dup( clean_up_path( cBuf ) );
}
/*
* Removes (deletes) a file.
*/
void shell_cmd_rm( TERM_DATA *pTerm, char *pArgument )
{
DIR *pDir;
FILE *pFile;
char cBuf[1024];
char cArg[MAX_INPUT];
pArgument = one_arg( pArgument, cArg );
strcpy( cArg, clean_up_path( cArg ) );
if ( cArg[0] == '\0' )
{
write_string_buffer( pTerm, "Usage: rm <file>\n\r\n\r" );
return;
}
if ( ( strlen( pShellDir ) + strlen( pTerm->pCurrentDir )
+ strlen( cArg ) + 1 ) > 1024 )
{
write_string_buffer( pTerm, "Path too long.\n\r\n\r" );
str_free( pTerm->pCurrentDir );
pTerm->pCurrentDir = EMPTY_STRING;
return;
}
if ( legal_path( pTerm, cArg ) != TRUE )
{
write_string_buffer( pTerm, "Illegal path.\n\r\n\r" );
return;
}
strcpy( cBuf, pShellDir );
strcat( cBuf, pTerm->pCurrentDir );
strcat( cBuf, cArg );
if ( ( pDir = opendir( cBuf ) ) != NULL )
{
if ( readdir( pDir ) != NULL )
{
closedir( pDir );
write_string_buffer( pTerm,
"File is a directory.\n\r\n\r" );
return;
}
closedir( pDir );
}
if ( ( pFile = fopen( cBuf, "r" ) ) == NULL )
{
write_string_buffer( pTerm, "No such file.\n\r\n\r" );
return;
}
fclose( pFile );
unlink( cBuf );
}
/*
* Creates a directory.
*/
void shell_cmd_mkdir( TERM_DATA *pTerm, char *pArgument )
{
char cBuf[1024];
char cArg[MAX_INPUT];
pArgument = one_arg( pArgument, cArg );
strcpy( cArg, clean_up_path( cArg ) );
if ( cArg[0] == '\0' )
{
write_string_buffer( pTerm,
"Usage: mkdir <directory name>\n\r\n\r" );
return;
}
if ( ( strlen( pShellDir ) + strlen( pTerm->pCurrentDir )
+ strlen( cArg ) + 1 ) > 1024 )
{
write_string_buffer( pTerm, "Path too long.\n\r\n\r" );
str_free( pTerm->pCurrentDir );
pTerm->pCurrentDir = EMPTY_STRING;
return;
}
if ( legal_path( pTerm, cArg ) != TRUE )
{
write_string_buffer( pTerm, "Illegal path.\n\r\n\r" );
return;
}
strcpy( cBuf, pShellDir );
strcat( cBuf, pTerm->pCurrentDir );
strcat( cBuf, cArg );
mkdir( cBuf, ( S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH ) );
}
/*
* Removes a directory.
*/
void shell_cmd_rmdir( TERM_DATA *pTerm, char *pArgument )
{
DIR *pDir;
char cBuf[1024];
char cArg[MAX_INPUT];
pArgument = one_arg( pArgument, cArg );
strcpy( cArg, clean_up_path( cArg ) );
if ( cArg[0] == '\0' )
{
write_string_buffer( pTerm,
"Usage: rmdir <directory>\n\r\n\r" );
return;
}
if ( ( strlen( pShellDir ) + strlen( pTerm->pCurrentDir )
+ strlen( cArg ) + 1 ) > 1024 )
{
write_string_buffer( pTerm, "Path too long.\n\r\n\r" );
str_free( pTerm->pCurrentDir );
pTerm->pCurrentDir = EMPTY_STRING;
return;
}
if ( legal_path( pTerm, cArg ) != TRUE )
{
write_string_buffer( pTerm, "Illegal path.\n\r\n\r" );
return;
}
strcpy( cBuf, pShellDir );
strcat( cBuf, pTerm->pCurrentDir );
strcat( cBuf, cArg );
if ( ( pDir = opendir( cBuf ) ) == NULL )
{
write_string_buffer( pTerm, "No such directory.\n\r\n\r" );
return;
}
if ( readdir( pDir ) == NULL )
{
closedir( pDir );
write_string_buffer( pTerm, "Not a directory.\n\r\n\r" );
return;
}
closedir( pDir );
if ( rmdir( cBuf ) == ENOTEMPTY )
write_string_buffer( pTerm, "Directory not empty.\n\r\n\r" );
}
/*
* Shows a directory listing.
*/
void shell_cmd_ls( TERM_DATA *pTerm, char *pArgument )
{
struct dirent *pDirEntry;
DIR *pDir;
char cBuf[1024];
char cArg[MAX_INPUT];
int iCount = 0;
pArgument = one_arg( pArgument, cArg );
strcpy( cArg, clean_up_path( cArg ) );
if ( ( strlen( pShellDir ) + strlen( pTerm->pCurrentDir )
+ strlen( cArg ) + 2 ) > 1024 )
{
write_string_buffer( pTerm, "Path too long.\n\r\n\r" );
str_free( pTerm->pCurrentDir );
pTerm->pCurrentDir = EMPTY_STRING;
return;
}
strcpy( cBuf, pShellDir );
strcat( cBuf, pTerm->pCurrentDir );
if ( cArg[0] != '\0' )
{
if ( legal_path( pTerm, cArg ) != TRUE )
{
write_string_buffer( pTerm, "Illegal path.\n\r\n\r" );
return;
}
strcat( cBuf, cArg );
}
else
strcat( cBuf, "." );
if ( ( pDir = opendir( cBuf ) ) == NULL )
{
write_string_buffer( pTerm, "No such directory.\n\r\n\r" );
return;
}
if ( readdir( pDir ) == NULL )
{
closedir( pDir );
write_string_buffer( pTerm, "Not a directory.\n\r\n\r" );
return;
}
readdir( pDir );
setup_string_pager( pTerm );
while ( ( pDirEntry = readdir( pDir ) ) != NULL )
{
sprintf( cBuf, "%-32.32s ", pDirEntry->d_name );
page_string( pTerm, cBuf );
iCount++;
if ( iCount == 2 )
{
page_string( pTerm, "\n\r" );
iCount = 0;
}
}
if ( iCount > 0 )
page_string( pTerm, "\n\r" );
page_string( pTerm, "\n\r" );
finish_string_pager( pTerm );
closedir( pDir );
}
/*
* Displays a file to the user.
*/
void shell_cmd_cat( TERM_DATA *pTerm, char *pArgument )
{
DIR *pDir;
FILE *pFile;
char cBuf[1024];
char cArg[MAX_INPUT];
int i;
pArgument = one_arg( pArgument, cArg );
strcpy( cArg, clean_up_path( cArg ) );
if ( cArg[0] == '\0' )
{
write_string_buffer( pTerm, "Usage: cat <input file>\n\r\n\r" );
return;
}
if ( ( strlen( pShellDir ) + strlen( pTerm->pCurrentDir )
+ strlen( cArg ) + 1 ) > 1024 )
{
write_string_buffer( pTerm, "Path too long.\n\r\n\r" );
str_free( pTerm->pCurrentDir );
pTerm->pCurrentDir = EMPTY_STRING;
return;
}
if ( legal_path( pTerm, cArg ) != TRUE )
{
write_string_buffer( pTerm, "Illegal path.\n\r\n\r" );
return;
}
strcpy( cBuf, pShellDir );
strcat( cBuf, pTerm->pCurrentDir );
strcat( cBuf, cArg );
if ( ( pDir = opendir( cBuf ) ) != NULL )
{
if ( readdir( pDir ) != NULL )
{
closedir( pDir );
write_string_buffer( pTerm,
"File is a directory.\n\r\n\r" );
return;
}
closedir( pDir );
}
if ( ( pFile = fopen( cBuf, "r" ) ) == NULL )
{
write_string_buffer( pTerm, "No such file.\n\r\n\r" );
return;
}
setup_string_pager( pTerm );
for ( i = 0; feof( pFile ) == 0; i++ )
{
if ( i == 256 )
{
cBuf[i] = '\0';
page_string( pTerm, cBuf );
i = 0;
}
cBuf[i] = getc( pFile );
}
cBuf[--i] = '\0';
if ( i > 0 )
page_string( pTerm, cBuf );
page_string( pTerm, "\n\r\n\r" );
finish_string_pager( pTerm );
fclose( pFile );
}
/*
* Shows a list of everyone logged onto the server.
*/
void shell_cmd_users( TERM_DATA *pTerm, char *pArgument )
{
TERM_DATA *pTerm2;
char cBuf[128];
setup_string_pager( pTerm );
for ( pTerm2 = pTermList; pTerm2 != NULL; pTerm2 = pTerm2->pNext )
{
sprintf( cBuf, "[%3d %3d] [%s] : %-50.50s\n\r",
pTerm2->sTelnetSocket, pTerm2->sBinarySocket,
state_string( pTerm2->iConState ), pTerm2->pHostname );
page_string( pTerm, cBuf );
}
page_string( pTerm, "\n\r" );
finish_string_pager( pTerm );
}
/*
* Shows a list of everyone in the development shell.
*/
void shell_cmd_who( TERM_DATA *pTerm, char *pArgument )
{
TERM_DATA *pTerm2;
char cBuf[128];
setup_string_pager( pTerm );
for ( pTerm2 = pTermList; pTerm2 != NULL; pTerm2 = pTerm2->pNext )
{
if ( pTerm2->iConState == CON_SYSTEM_SHELL
&& pTerm2->pChar != NULL )
{
sprintf( cBuf, "%-14.14s - %s\n\r",
pTerm2->pChar->pPCData->sName, pTerm2->pHostname );
page_string( pTerm, cBuf );
}
}
page_string( pTerm, "\n\r" );
finish_string_pager( pTerm );
}
/*
* Sends a message to another user in the development shell.
*/
void shell_cmd_tell( TERM_DATA *pTerm, char *pArgument )
{
TERM_DATA *pToTerm;
char cArg[MAX_INPUT];
char cBuf[MAX_STRING];
pArgument = one_arg( pArgument, cArg );
if ( cArg[0] == '\0' || pArgument[0] == '\0' )
{
write_string_buffer( pTerm,
"Usage: tell <name> <message>\n\r\n\r" );
return;
}
for ( pToTerm = pTermList; pToTerm != NULL;
pToTerm = pToTerm->pNext )
{
if ( pToTerm->iConState == CON_SYSTEM_SHELL
&& pToTerm->pChar != NULL
&& multi_compare( cArg, pToTerm->pChar->pPCData->sName )
== TRUE )
break;
}
if ( pToTerm == NULL )
{
write_string_buffer( pTerm, "Party not found.\n\r\n\r" );
return;
}
if ( pToTerm == pTerm )
{
write_string_buffer( pTerm,
"Must be someone besides yourself.\n\r\n\r" );
return;
}
if ( pTerm->pChar != NULL )
snprintf( cBuf, MAX_STRING, "\n\r%s tells you: %s\n\r\n\r",
pTerm->pChar->pPCData->sName, pArgument );
else
snprintf( cBuf, MAX_STRING, "\n\rSomeone tells you: %s\n\r\n\r",
pTerm->pChar->pPCData->sName, pArgument );
write_string_buffer( pToTerm, cBuf );
write_string_buffer( pTerm, "Message sent.\n\r\n\r" );
}
/*
* End of shell.c
*/