/* * 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 */