Mercurial > audlegacy
changeset 709:f4af4f87850e trunk
[svn] Move inetctl out into the hacking zone as it needs conversion to a threading model instead of it just forking things.
author | chainsaw |
---|---|
date | Sun, 26 Feb 2006 16:14:17 -0800 |
parents | e4069b00b174 |
children | 500f6d54bc46 |
files | Plugins/General/inetctl/Makefile.in Plugins/General/inetctl/config.h.in Plugins/General/inetctl/inetctl.c Plugins/General/inetctl/inetctl.h Plugins/General/inetctl/inetctl_actions.c Plugins/General/inetctl/inetctl_client.c Plugins/General/inetctl/inetctl_command.c Plugins/General/inetctl/inetctl_config.c Plugins/General/inetctl/inetctl_status.c |
diffstat | 9 files changed, 0 insertions(+), 2127 deletions(-) [+] |
line wrap: on
line diff
--- a/Plugins/General/inetctl/Makefile.in Sun Feb 26 15:50:50 2006 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -include ../../../mk/rules.mk -include ../../../mk/objective.mk - -OBJECTIVE_LIBS = libinetctl.so - -LIBDIR = $(plugindir)/$(GENERAL_PLUGIN_DIR) - -SOURCES = inetctl.c inetctl_actions.c inetctl_client.c inetctl_command.c inetctl_config.c inetctl_status.c - -CFLAGS += -fPIC -DPIC $(GTK_CFLAGS) -I../../../intl -I../../.. - -OBJECTS = ${SOURCES:.c=.o}
--- a/Plugins/General/inetctl/config.h.in Sun Feb 26 15:50:50 2006 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* config.h.in. Generated automatically from configure.in by autoheader. */ - -/* Define if you have the xmms_remote_get_balance function. */ -#undef HAVE_XMMS_REMOTE_GET_BALANCE - -/* Define if you have the xmms_remote_get_info function. */ -#undef HAVE_XMMS_REMOTE_GET_INFO - -/* Define if you have the xmms_remote_get_main_volume function. */ -#undef HAVE_XMMS_REMOTE_GET_MAIN_VOLUME - -/* Define if you have the xmms_remote_get_output_time function. */ -#undef HAVE_XMMS_REMOTE_GET_OUTPUT_TIME - -/* Define if you have the xmms_remote_get_playlist_pos function. */ -#undef HAVE_XMMS_REMOTE_GET_PLAYLIST_POS - -/* Define if you have the xmms_remote_get_playlist_time function. */ -#undef HAVE_XMMS_REMOTE_GET_PLAYLIST_TIME - -/* Define if you have the xmms_remote_get_playlist_title function. */ -#undef HAVE_XMMS_REMOTE_GET_PLAYLIST_TITLE - -/* Define if you have the xmms_remote_is_paused function. */ -#undef HAVE_XMMS_REMOTE_IS_PAUSED - -/* Define if you have the xmms_remote_is_playing function. */ -#undef HAVE_XMMS_REMOTE_IS_PLAYING - -/* Define if you have the xmms_remote_is_repeat function. */ -#undef HAVE_XMMS_REMOTE_IS_REPEAT - -/* Define if you have the xmms_remote_is_shuffle function. */ -#undef HAVE_XMMS_REMOTE_IS_SHUFFLE - -/* Define if you have the xmms_remote_pause function. */ -#undef HAVE_XMMS_REMOTE_PAUSE - -/* Define if you have the xmms_remote_play function. */ -#undef HAVE_XMMS_REMOTE_PLAY - -/* Define if you have the xmms_remote_playlist_next function. */ -#undef HAVE_XMMS_REMOTE_PLAYLIST_NEXT - -/* Define if you have the xmms_remote_playlist_prev function. */ -#undef HAVE_XMMS_REMOTE_PLAYLIST_PREV - -/* Define if you have the xmms_remote_set_balance function. */ -#undef HAVE_XMMS_REMOTE_SET_BALANCE - -/* Define if you have the xmms_remote_set_main_volume function. */ -#undef HAVE_XMMS_REMOTE_SET_MAIN_VOLUME - -/* Define if you have the xmms_remote_stop function. */ -#undef HAVE_XMMS_REMOTE_STOP - -/* Define if you have the xmms_remote_toggle_repeat function. */ -#undef HAVE_XMMS_REMOTE_TOGGLE_REPEAT - -/* Define if you have the xmms_remote_toggle_shuffle function. */ -#undef HAVE_XMMS_REMOTE_TOGGLE_SHUFFLE
--- a/Plugins/General/inetctl/inetctl.c Sun Feb 26 15:50:50 2006 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,498 +0,0 @@ -/* - xmms_inetctl - Network control port for XMMS - Copyright (C) 2002 Gerald Duprey <gerry@cdp1802.org> - based on xmms-mpcp by Vadim "Kryptolus" Berezniker <vadim@berezniker.com> - in turn, based on work from xmms-goodnight - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -/* The protocol looks much like the FTP protocol. All commands and responses */ -/* are line oriented text. Commands are in upper case. Responses have a */ -/* numeric code indentifying the response, followed by parameters. Each token */ -/* is seperated by a space. Parameters can be enclosed by single or double */ -/* quotes, especially important when the parameter has embedded spaces. The */ -/* line must be terminated with a CR and LF (ASCII 0x0d, then 0x0a). Extra */ -/* spaces between parameters are ignored. Blank lines or lines begining with */ -/* a # are ignored by the server. Responses can be solicited (i.e. in reply */ -/* to a REQUEST command) or unsolicited (i.e. in response to the server */ -/* moving on to a new track). There is no guarantee that the first response */ -/* the client receives after sending a command is in anyway related to that */ -/* command (i.e. you can't send a REQUEST CUR_TRACK and assume the next reply */ -/* the server sends is the track info). Stateless is the way to go here. */ - -/* Commands: - * USER name PASSWORD word - Authenticate user - * PLAY - Resume playing (after pause or stop) - * PLAY_FILE path/filename.mp3 - Load and play the file. There can be multiple - * files and the files can be MP3s and M3Us - * Any existing playlist is cleared first. - * LOAD_FILE path/filename.m3u - Load the file. This is the same as PLAY_FILE - * except it won't automatically start playing - * after loading. - * PAUSE - Pauses playing - * RESUME - Result playing (same as PLAY) - * NEXT_TRACK - Move on to next track - * PREV_TRACK - Move back to previous track - * STOP - Stops player - * EXIT - Closes this connection - * QUIT - Closes connection and shutdown XMMS - * VOLUME n - Sets volume to n% (0-100, 0=Mute) - * SHUFFLE on/off - Sets shuffle mode on or off - * REPEAT on/off - Sets play repeat mode on or off - * - * Per Client commands (these affect only your connection) - * TIME_UPDATES on/off - Sets progress in time messages are sent during play (default on) - * FORMATTED_TIME on/off - Sets whether time reports are formatted (h:mm:ss) or - * just raw seconds. Default is on. - * REQUEST STATUS - Returns player status - * REQUEST TRACK - Returns current track info via 011 - * REQUEST PLAYLIST - Returns current playlist info via 012 - * REQUEST POSITION - Returns current position in song via 013 - * REQUEST ALL - Causes all status (010-019) to be returned in order - */ - -/* Responses: - * - * NOTE: Future versions will not change the data being sent, but MAY - * add additional parameters on to the end of the status. Don't assume - * that the number of parameters will never change. It won't get - * smaller, but it may grow. As long as you can handle that (and - * ignore it until your code is reved to support the new stuff), you'll - * be fine. - * - * Times are always represented in hours:minutes:seconds. Minutes - * and seconds will always be two digitis. Hours will be as - * many digits as necessary, but always at least one (for 0). - - * 000 - Welcome/connection message - * 000 hostname XMMS_NETCTL server (Version theversion) ready. - * 000 homer.cdp1802.org XMMS_NETCTL server (Version V0.2.0) ready. - * 001 - Authentication needed/failure indicator - * 001 NOT AUTHENTICATED - * 002 - Unrecognized command or parameters - * 002 UNKNOWN COMMAND - * 003 - Too few/many arguments - * 003 TOO FEW ARGUMENTS - * 004 - Unrecognized Argument/invalid argument - * 004 INVALID ARGUMENT - * - * 010 - Current player status - * 010 state volume shuffle_mode repeat_mode - * 010 PLAYING 100 SHUFFLE REPEAT - * 011 - Current track info - * 011 title filename length rate freq chans - * 011 "They Might Be Giants - Twisting" "/usr/opt/mp3/tmbg/flood/twisting.mp3" 0:1:57 128 44 2 - * 012 - Current Playlist info - * 012 curtrack totaltracks - * 012 5 104 - * 013 - Track playing status update - * 013 timeintrack totaltracktime - * 013 0:01:20 0:04:31 - */ - -/* Include commons */ -#include "inetctl.h" - -/* Define client managment structures */ -struct _clientDef { - pid_t clientPID; - int clientSocket; -}; -typedef struct _clientDef clientDef; -typedef struct _clientDef * clientDefPtr; - -/* Port we wait for connections on */ -int listenPort = 1586; -int listenSocket = -1; - -/* Status flags */ -Bool debugMode = FALSE; -Bool inetctlEnabled = TRUE; -pid_t serverPID = -1; - -/* Plugin definition structure */ -GeneralPlugin inetctl = { - NULL, - NULL, - -1, - "iNetControl " INETCTLVERSION, - inetctl_init, - inetctl_about, - inetctl_config, - inetctl_cleanup, -}; - -/* Define client tracking */ -#define CLIENT_MAX 64 -int clientCount = 0; -clientDef clientInfo[CLIENT_MAX]; - -/* Define formatting buffer */ -#define FORMAT_BUFFER_MAX 1024 -char formatBuffer[FORMAT_BUFFER_MAX]; - -/* Forward declarations */ -Bool removeClient(int); -Bool acceptNewClients(int); -Bool configureServer(); - -/* Shutdown the server */ -void shutdownServer() { - int clientIndex; - - writeDebug("Shutting down server\n"); - - /* Shutdown all children first */ - for (clientIndex = clientCount - 1; clientIndex >= 0; clientIndex--) { - removeClient(clientInfo[clientIndex].clientPID); - } - - /* Close socket */ - if (listenSocket != -1) { - close(listenSocket); - listenSocket = -1; - } - - /* Now we stop ourselves/server */ - if (serverPID != -1) { - writeDebug("Killing server process %d\n", getpid()); - kill(getpid(), SIGKILL); - serverPID = -1; - } -} - -/* Remove an existing client from the client list */ -Bool removeClient(int theClientPID) { - int clientIndex; - int purgeIndex; - - for (clientIndex = 0; clientIndex < clientCount; clientIndex++) { - /* See if this is our client */ - if (clientInfo[clientIndex].clientPID == theClientPID) { - /* Close the connection */ - close(clientInfo[clientIndex].clientSocket); - - /* Kill the client */ - kill(clientInfo[clientIndex].clientPID, SIGKILL); - - /* Shift all other clients down */ - for (purgeIndex = clientIndex; purgeIndex < (clientCount - 1); purgeIndex++) - clientInfo[purgeIndex] = clientInfo[purgeIndex + 1]; - - /* Down the client count & we ar done */ - clientCount--; - writeDebug("Removed client %d, %d clients remaining\n", theClientPID, clientCount); - return TRUE; - } - } - - /* If we got here, there was no match */ - return FALSE; -} - -/* Add the passed client to the list */ -Bool addClient(pid_t theClientPID, int theClientSocket) { - /* Make sure there is room */ - if (clientCount == CLIENT_MAX) return FALSE; - - /* Add in info */ - clientInfo[clientCount].clientPID = theClientPID; - clientInfo[clientCount].clientSocket = theClientSocket; - clientCount++; - - writeDebug("Spawned child %d to handle client, now %d clients\n", theClientPID, clientCount); - - return TRUE; -} - -/* Handle termination signal */ -void termHandler(int sigNum) { - shutdownServer(); - return; -} - -/* Handle children ending/dying */ -void mournChildren(int sigNum) { - int childPID, childStatus; - - /* Check for any child processes that have "silently" died */ - while ((childPID = waitpid(-1, &childStatus, WNOHANG))) { - /* No children means just get the heck out (quietly) */ - if ((childPID < 0) && (errno == 10)) break; - - /* Handle an error */ - if (childPID < 0) { - writeError("Error while mourning children, %s (%d)\n", strerror(errno), errno); - } else { - /* We are done */ - removeClient(childPID); - writeDebug("Recognized that child %d died\n", childPID); - } - } - - /* Resinstall handler */ - signal(SIGCHLD, mournChildren); -} - -/* Write a message when in debug mode */ -void writeDebug(String theFormat, ...) { - va_list theParms; - - /* Skip out if not debugging */ - if (!debugMode) return; - - /* Format and print message */ - va_start(theParms, theFormat); - fprintf(stderr, "inetctl DEBUG [%6d]: ", getpid()); - vfprintf(stderr, theFormat, theParms); - va_end(theParms); -} - -/* Write an error message */ -void writeError(String theFormat, ...) { - va_list theParms; - - /* Format and print message */ - va_start(theParms, theFormat); - fprintf(stderr, "inetctl ERROR [%6d]: ", getpid()); - vfprintf(stderr, theFormat, theParms); - va_end(theParms); -} - -GeneralPlugin * get_gplugin_info () { - writeDebug("XMMS Asked for inetctl info\n"); - return (&inetctl); -} - -void inetctl_cleanup() { - int serverStatus = -1; - - writeDebug("Cleanup module started\n"); - - /* Clear enabled indicator */ - inetctlEnabled = FALSE; - - /* Shutdown the server and free resources */ - if (serverPID != -1) { - writeDebug("Shuttingdown inetctl server\n"); - kill(serverPID, SIGTERM); - waitpid(serverPID, &serverStatus, 0); - } - - writeDebug("Module cleanup complete\n"); -} - -/* Initialize this module */ -void inetctl_init() { - int errval; - int reuseFlag = 1; - struct sockaddr_in server; - struct protoent * tcpInfo; - - writeDebug("Begining module initialization\n"); - - /* lookup tcp protocol info */ - tcpInfo = getprotobyname("tcp"); - if (tcpInfo == NULL) { - writeError("Unable lookup info on TCP protocol\n"); - exit(1); - } - - /* Read the configuration for this module */ - read_config(); - - /* create the main socket */ - listenSocket = socket(PF_INET, SOCK_STREAM, tcpInfo->p_proto); - setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, &reuseFlag, sizeof(reuseFlag)); - server.sin_family = AF_INET; - server.sin_addr.s_addr = htonl(INADDR_ANY); - server.sin_port = htons(listenPort); - - /* bind the socket */ - if ((errval = bind(listenSocket, (struct sockaddr *) &server, sizeof(server))) == -1) { - writeError("Attempt to bind to port %d failed - %s (%d)\n", - listenPort, strerror(errno), errno); - close(listenSocket); - listenSocket = -1; - return; - } - - /* Initiate active listening on our port */ - if ((errval = listen(listenSocket, 10)) == -1) { - writeError("Attempt to listen on port %d failed - %s (%d)\n", - listenPort, strerror(errno), errno); - close(listenSocket); - listenSocket = -1; - exit(1); - } - - /* Install a child death handler */ - signal(SIGCHLD, mournChildren); - - /* Fork off server */ - switch(serverPID = fork()) { - case -1: - writeError("Attempt to fork failed - %s (%d)\n", strerror(errno), errno); - close(listenSocket); - listenSocket = -1; - exit(1); - break; - - case 0: - /* Configure the server */ - configureServer(); - - /* Process client connections */ - writeDebug("Now ready to accept client connections\n"); - acceptNewClients(listenSocket); - shutdownServer(); - break; - - default: - writeDebug("Server installed as PID %d\n", serverPID); - close(listenSocket); - listenSocket = -1; - break; - } - - /* Flag ourselves (re)initialized */ - inetctlEnabled = TRUE; - - writeDebug("Intialization complete\n"); -} - -/* Do one-shot server initialization */ -Bool configureServer() { - /* Get our PID */ - serverPID = getpid(); - - /* Install us as the process group leader */ - setpgrp(); - - /* Catch requests for us to shut down */ - signal(SIGTERM, termHandler); - - /* Initialize status tracking */ - if (!initStatusTracking()) return FALSE; - - /* Server ready to rock and roll */ - return TRUE; -} - -/* Check if the recently connected client, described by clientInfo, */ -/* is valid (i.e. matches any security we have installed). If so, */ -/* return TRUE. Otherwise, return FALSE. */ -Bool isValidClient(struct sockaddr_in * clientInfo) { - /* For now, we are disabling authentication */ - userAuthenticated = TRUE; - userName = "TEST"; - - /* IP Security and such would go here */ - return TRUE; -} - -/* Client connection handlers inherit lots of stuff we */ -/* not need or want from the server. Here we drop that*/ -/* which isn't needed for a client */ -void closeInheritedResources() { - int clientIndex; - - /* Close servers listen socket, if open */ - if (listenSocket != -1) close(listenSocket); - listenSocket = -1; - - /* Close any clients too */ - for (clientIndex = 0; clientIndex < clientCount; clientIndex++) { - close(clientInfo[clientIndex].clientSocket); - clientInfo[clientIndex].clientSocket = -1; - clientInfo[clientIndex].clientPID = -1; - } - clientCount = 0; -} - -/* Process incoming client connections. Each incoming connection */ -/* gets it own process to handle the connection. */ -Bool acceptNewClients(int mainSocket) { - int errval; - pid_t clientPID; - int clientSocket; - socklen_t len; - struct pollfd connWait; - struct sockaddr_in client; - - /* Initialize polling wait structure */ - connWait.fd = mainSocket; - connWait.events = POLLIN; - - /* We repeatedly process incomming connections */ - while(inetctlEnabled) { - /* Wait for a new connection */ - SYSCALL(errval = poll(&connWait, 1, -1)); - if (errval == -1) { - writeError("Poll waiting for new connections failed - %s (%d)\n", - strerror(errno), errno); - return FALSE; - } - - /* See if we got a timeout */ - if (errval == 0) { - updatePlayerStatus(-1); - continue; - } - - /* Accept a new connection */ - if ((clientSocket = accept(mainSocket, (struct sockaddr *) &client, &len)) == -1) { - writeError("Unable to accept new client connection - %s (%d)\n", - strerror(errno), errno); - continue; - } - - /* Do security checks on this connection */ - if (!isValidClient(&client)) { - writeDebug("Closing client connection - failed security check\n"); - close(clientSocket); - clientSocket = -1; - continue; - } - - /* Fork off a child to handle this client connection */ - switch(clientPID = fork()) { - case -1: - writeError("Attempt to form new client connection failed - %s (%d)\n", - strerror(errno), errno); - return FALSE; - break; - - case 0: - /* Close off inherited resources */ - closeInheritedResources(); - - /* Handle this clients traffic */ - processClientRequests(getpid(), clientSocket); - removeClient(clientPID); - exit(0); - break; - - default: - /* We've handed that client off to the child - close ours */ - addClient(clientPID, clientSocket); - break; - } - } - - /* Processing completed */ - return TRUE; -}
--- a/Plugins/General/inetctl/inetctl.h Sun Feb 26 15:50:50 2006 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,133 +0,0 @@ -/* inetctl.h - common includes for inetctl */ - -#include <gtk/gtk.h> -#include <netdb.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <sys/poll.h> -#include <asm/errno.h> -#include <netinet/in.h> -#include <errno.h> -#include <unistd.h> -#include <gtk/gtk.h> - -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <signal.h> -#include <time.h> -#include <glib.h> -#include <string.h> -#include <ctype.h> -#include "libaudacious/beepctrl.h" -#include "libaudacious/configdb.h" -#include "audacious/plugin.h" - -#include "config.h" - -#define INETCTLVERSION "1.2" -#define INETCTLVERSION_MAJOR 1 -#define INETCTLVERSION_MINOR 2 -#define INETCTLVERSION_MICRO 0 - -#define CONFIGFILE "/.xmms/inetctl" - -#define SYSCALL(call) while(((int) (call) == -1) && (errno == EINTR)) - -typedef char * String; - -typedef int Bool; -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif - -/* Port we wait for connections on */ -extern int listenPort; -extern pid_t serverPID; - -/* Status flags */ -extern Bool debugMode; -extern Bool inetctlEnabled; - -/* User flags */ -extern Bool userAuthenticated; -extern String userName; - -/* Command dispatch table */ -typedef Bool (* _cmdFunc)(int, String[]); -struct _cmdTable { - char commandName[32]; - _cmdFunc commandFunc; - Bool alwaysAllowed; -}; -typedef struct _cmdTable cmdTable; -typedef struct _cmdTable * cmdTablePtr; - -extern cmdTable commandTable[]; - -/* Player status info */ -#define PLAYER_TEXT_MAX 512 -struct _playerStatDef { - Bool infoValid; - - /* Playlist info */ - gint curTrackInPlaylist; - gint totalTracksInPlaylist; - - /* Track Info */ - gint curTrackLength; - gint curTrackTime; - char trackTitle[PLAYER_TEXT_MAX]; - char trackFile[PLAYER_TEXT_MAX]; - - /* Player info */ - gint volume, balance; - gboolean playing, paused, repeat, shuffle; -}; -typedef struct _playerStatDef playerStatus; -typedef struct _playerStatDef * playerStatusPtr; - -extern GeneralPlugin inetctl; - -/* Public methods invoked by xmms (from inetctl.c) */ -extern void inetctl_init(); -extern void inetctl_about(); -extern void inetctl_config(); -extern void inetctl_cleanup(); - -/* Support functions in inetctl.c */ -extern void writeDebug(String, ...); -extern void writeError(String, ...); - -/* Command parse in inetctl_command.c */ -extern void upString(String); -extern void trimString(String); -extern Bool dispatchCommand(String); -extern void endThisClient(); - -/* Configuration support in inetctl_config.c */ -extern void read_config(); - -/* Client support in inetctl_client.c */ -extern Bool sendResponse(String, String, ...); -extern void processClientRequests(pid_t, int); - -/* Status support in inetctl_status.c */ -extern playerStatus lastPlayerStatus; -extern Bool initStatusTracking(); -extern Bool updatePlayerStatus(int); -extern Bool sendNewClientStatus(int); -extern void setFormattedTime(Bool); -extern Bool isFormattedTime(); -extern void setTimeUpdates(Bool); -extern void setPlaylistUpdates(Bool); -extern Bool freshenClientStatus(); -extern Bool sendPlayerStatus(playerStatusPtr); -extern Bool sendPlaylistStatus(playerStatusPtr); -extern Bool sendPlaylistTracks(playerStatusPtr); -extern Bool sendTrackInfo(playerStatusPtr); -extern Bool sendTrackStatus(playerStatusPtr); - -
--- a/Plugins/General/inetctl/inetctl_actions.c Sun Feb 26 15:50:50 2006 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,444 +0,0 @@ -/* inetctl_actions.c - This is where commands are interpreted and acted on */ - -/* For simplciity of installation, the actual command dispatch table */ -/* is defined at the end of the source file. This is done because other */ -/* wise we'd have to have lots of forward references. */ - -/* I really wanted the COMMAND macro to not only define the function, but */ -/* also add the function to the command dispatch table, but I couldn't */ -/* find a way to build up a list that would later be expanded. */ - -/* As a result, a new command requires two definitions. The COMMMAND def */ -/* defines the name of the command and the function header for the code */ -/* executed for that command. The REGISTER macro, located at the end of */ -/* the file, adds the command to the dispatch table. The names in the */ -/* COMMAND macros must match the names in the REGISTER macros or you'll */ -/* either get undefined symbols or functions that are never invoked. */ - -#include "inetctl.h" - -/* Exported from inetctl_client.c */ -extern pid_t clientPID; -extern int clientSocket; - -#define COMMAND(NAME) Bool cmd_##NAME(int argc, String argv[]) -#define REGISTER(NAME, PUBLIC) { #NAME, cmd_##NAME, PUBLIC } - -COMMAND(DEBUG) { - Bool debugFlag = TRUE; - - /* If there is a parameter, process it */ - if (argc >= 2) { - upString(argv[1]); - if (!strcmp(argv[1], "OFF")) debugFlag = FALSE; - } - - debugMode = debugFlag; - return TRUE; -} - -COMMAND(USER) { - return TRUE; -} - -COMMAND(PLAY) { - xmms_remote_play(inetctl.xmms_session); - return TRUE; -} - -COMMAND(PLAY_FILE) { - int argIndex; - GList *theList = NULL; - - /* Add all files to the list */ - for (argIndex = 1; argIndex < argc; argIndex++) { - theList = g_list_append(theList, argv[argIndex]); - } - - /* Insure there is at least one file */ - if (theList == NULL) { - sendResponse("003", "TOO FEW ARGUMENTS"); - return FALSE; - } - - /* Clear the current list and add these file(s) to it */ - xmms_remote_stop(inetctl.xmms_session); - xmms_remote_playlist_clear(inetctl.xmms_session); - xmms_remote_playlist_add(inetctl.xmms_session, theList); - xmms_remote_play(inetctl.xmms_session); - - /* And we are off to the races */ - return TRUE; -} - -COMMAND(LOAD_FILE) { - int argIndex; - GList *theList = NULL; - - /* Add all files to the list */ - for (argIndex = 1; argIndex < argc; argIndex++) { - theList = g_list_append(theList, argv[argIndex]); - } - - /* Insure there is at least one file */ - if (theList == NULL) { - sendResponse("003", "TOO FEW ARGUMENTS"); - return FALSE; - } - - /* Clear the current list and add these file(s) to it */ - xmms_remote_stop(inetctl.xmms_session); - xmms_remote_playlist_clear(inetctl.xmms_session); - xmms_remote_playlist_add(inetctl.xmms_session, theList); - - /* And we are off to the races */ - return TRUE; -} - -COMMAND(CLEAR_PLAYLIST) { - int trackIndex; - - /* Stop the player (if playing) */ - xmms_remote_stop(inetctl.xmms_session); - - /* Clear the current list and add these file(s) to it */ - for (trackIndex = lastPlayerStatus.totalTracksInPlaylist - 1; trackIndex >= 0; trackIndex--) { - xmms_remote_playlist_delete(inetctl.xmms_session, trackIndex); - } - - return TRUE; -} - -COMMAND(APPEND_FILE) { - int argIndex; - GList *theList = NULL; - - /* Add all files to the list */ - for (argIndex = 1; argIndex < argc; argIndex++) { - theList = g_list_append(theList, argv[argIndex]); - } - - /* Insure there is at least one file */ - if (theList == NULL) { - sendResponse("003", "TOO FEW ARGUMENTS"); - return FALSE; - } - - /* Append this to the current list */ - xmms_remote_playlist_add(inetctl.xmms_session, theList); - return TRUE; -} - -COMMAND(REMOVE_TRACK) { - int theTrackNum; - String theEndChar; - - /* Convert integer to number */ - theTrackNum = strtol(argv[1], &theEndChar, 10); - if ((*theEndChar != '\0') - || (theEndChar == argv[1]) - || (theTrackNum < 0) - || (theTrackNum >= lastPlayerStatus.totalTracksInPlaylist)) { - sendResponse("004", "INVALID ARGUMENT"); - return FALSE; - } - - xmms_remote_playlist_delete(inetctl.xmms_session, theTrackNum); - return TRUE; -} - -COMMAND(PAUSE) { - if (xmms_remote_is_playing(inetctl.xmms_session) - && !xmms_remote_is_paused(inetctl.xmms_session)) { - xmms_remote_pause(inetctl.xmms_session); - } - - return TRUE; -} - -COMMAND(RESUME) { - if (xmms_remote_is_playing(inetctl.xmms_session) - && xmms_remote_is_paused(inetctl.xmms_session)) { - xmms_remote_pause(inetctl.xmms_session); - } - - return TRUE; -} - -COMMAND(STOP) { - xmms_remote_stop(inetctl.xmms_session); - return TRUE; -} - -COMMAND(NEXT_TRACK) { - int theRepeatCount = 1, theCount = 0; - String theEndChar; - - /* Convert integer to number */ - if (argc == 2) { - theRepeatCount = strtol(argv[1], &theEndChar, 10); - if ((*theEndChar != '\0') - || (theEndChar == argv[1]) - || (theRepeatCount < 1)) { - sendResponse("004", "INVALID ARGUMENT"); - return FALSE; - } - } - - for (theCount = 0; theCount < theRepeatCount; theCount++) - xmms_remote_playlist_next(inetctl.xmms_session); - - return TRUE; -} - -COMMAND(PREV_TRACK) { - int theRepeatCount = 1, theCount = 0; - String theEndChar; - - /* Convert integer to number */ - if (argc == 2) { - theRepeatCount = strtol(argv[1], &theEndChar, 10); - if ((*theEndChar != '\0') - || (theEndChar == argv[1]) - || (theRepeatCount < 1)) { - sendResponse("004", "INVALID ARGUMENT"); - return FALSE; - } - } - - for (theCount = 0; theCount < theRepeatCount; theCount++) - xmms_remote_playlist_prev(inetctl.xmms_session); - - return TRUE; -} - -COMMAND(JUMP_TO_TRACK) { - int theTrackNum; - String theEndChar; - - /* Convert integer to number */ - theTrackNum = strtol(argv[1], &theEndChar, 10); - if ((*theEndChar != '\0') - || (theEndChar == argv[1]) - || (theTrackNum < 0) - || (theTrackNum >= lastPlayerStatus.totalTracksInPlaylist)) { - sendResponse("004", "INVALID ARGUMENT"); - return FALSE; - } - - xmms_remote_set_playlist_pos(inetctl.xmms_session, theTrackNum); - return TRUE; -} - -COMMAND(JUMP_TO_TIME) { - int theTimeIndex; - String theEndChar; - - /* Convert integer to number */ - theTimeIndex = strtol(argv[1], &theEndChar, 10); - if ((*theEndChar != '\0') - || (theEndChar == argv[1]) - || (theTimeIndex < 0) - || (theTimeIndex >= lastPlayerStatus.curTrackLength)) { - sendResponse("004", "INVALID ARGUMENT"); - return FALSE; - } - - if (isFormattedTime()) - xmms_remote_jump_to_time(inetctl.xmms_session, theTimeIndex * 1000); - else - xmms_remote_jump_to_time(inetctl.xmms_session, theTimeIndex); - - return TRUE; -} - -COMMAND(EXIT) { - endThisClient(); - return FALSE; -} - -COMMAND(QUIT) { - xmms_remote_quit(inetctl.xmms_session); - kill(serverPID, SIGTERM); - return FALSE; -} - -COMMAND(REPEAT) { - Bool repeatMode = TRUE; - - /* If there is a parameter, process it */ - if (argc >= 2) { - upString(argv[1]); - if (!strcmp(argv[1], "OFF")) repeatMode = FALSE; - } - - /* See if we need to change repeat mode */ - if (xmms_remote_is_repeat(inetctl.xmms_session) == repeatMode) - return TRUE; - - /* Toggle repeat mode */ - xmms_remote_toggle_repeat(inetctl.xmms_session); - return TRUE; -} - -COMMAND(SHUFFLE) { - Bool shuffleMode = TRUE; - - /* If there is a parameter, process it */ - if (argc >= 2) { - upString(argv[1]); - if (!strcmp(argv[1], "OFF")) shuffleMode = FALSE; - } - - /* See if we need to change shuffle mode */ - if (xmms_remote_is_shuffle(inetctl.xmms_session) == shuffleMode) - return TRUE; - - /* Toggle shuffle mode */ - xmms_remote_toggle_shuffle(inetctl.xmms_session); - return TRUE; -} - -COMMAND(VOLUME) { - int newVolume; - String endChar; - - /* There must be an additional parameter */ - if (argc != 2) { - sendResponse("003", "TOO FEW ARGUMENTS"); - return FALSE; - } - - /* Convert to volume */ - trimString(argv[1]); - newVolume = strtol(argv[1], &endChar, 10); - if ((endChar == argv[1]) || (*endChar != '\0') || (newVolume < 0) || (newVolume > 100)) { - sendResponse("004", "INVALID ARGUMENT"); - return FALSE; - } - - /* Install new volume */ - xmms_remote_set_main_volume(inetctl.xmms_session, newVolume); - return TRUE; -} - -COMMAND(HIDE_PLAYER) { - /* Set Players Visibility */ - xmms_remote_pl_win_toggle(inetctl.xmms_session, FALSE); - xmms_remote_eq_win_toggle(inetctl.xmms_session, FALSE); - xmms_remote_main_win_toggle(inetctl.xmms_session, FALSE); - return TRUE; -} - -COMMAND(TIME_UPDATES) { - Bool timeUpdates = TRUE; - - /* If there is a parameter, process it */ - if (argc >= 2) { - upString(argv[1]); - if (!strcmp(argv[1], "OFF")) timeUpdates = FALSE; - } - - /* See if we need to change flag */ - setTimeUpdates(timeUpdates); - return TRUE; -} - -COMMAND(PLAYLIST_UPDATES) { - Bool playlistUpdates = TRUE; - - /* If there is a parameter, process it */ - if (argc >= 2) { - upString(argv[1]); - if (!strcmp(argv[1], "OFF")) playlistUpdates = FALSE; - } - - /* See if we need to change flag */ - setPlaylistUpdates(playlistUpdates); - return TRUE; -} - - -COMMAND(FORMATTED_TIME) { - Bool formattedTime = TRUE; - - /* If there is a parameter, process it */ - if (argc >= 2) { - upString(argv[1]); - if (!strcmp(argv[1], "OFF")) formattedTime = FALSE; - } - - /* See if we need to change flag */ - writeDebug("Setting formatted time to %d\n", formattedTime); - setFormattedTime(formattedTime); - return TRUE; -} - -COMMAND(REQUEST) { - /* There must be an additional parameter */ - if (argc != 2) { - sendResponse("003", "TOO FEW ARGUMENTS"); - return FALSE; - } - - /* Upcase our option */ - upString(argv[1]); - - /* Freshen the clients stats */ - freshenClientStatus(); - - /* Dispatch it */ - if (!strcmp(argv[1], "STATUS")) - return sendPlayerStatus(NULL); - else if (!strcmp(argv[1], "TRACK")) - return sendTrackInfo(NULL); - else if (!strcmp(argv[1], "PLAYLIST")) - return sendPlaylistStatus(NULL); - else if (!strcmp(argv[1], "POSITION")) - return sendTrackStatus(NULL); - else if (!strcmp(argv[1], "ALL")) { - sendPlayerStatus(NULL); - sendTrackInfo(NULL); - sendPlaylistStatus(NULL); - sendTrackStatus(NULL); - } else if (!strcmp(argv[1], "PLAYLIST_TRACKS")) - return sendPlaylistTracks(NULL); - else { - sendResponse("004", "UNRECOGNIZED ARGUMENT"); - return FALSE; - } - - return TRUE; -} - -/* Build command table */ -cmdTable commandTable[] = { - REGISTER(DEBUG, FALSE), - REGISTER(USER, TRUE), - REGISTER(PLAY, FALSE), - REGISTER(PLAY_FILE, FALSE), - REGISTER(LOAD_FILE, FALSE), - REGISTER(APPEND_FILE, FALSE), - REGISTER(REMOVE_TRACK, FALSE), - REGISTER(CLEAR_PLAYLIST, FALSE), - REGISTER(PAUSE, FALSE), - REGISTER(RESUME, FALSE), - REGISTER(NEXT_TRACK, FALSE), - REGISTER(PREV_TRACK, FALSE), - REGISTER(JUMP_TO_TRACK, FALSE), - REGISTER(JUMP_TO_TIME, FALSE), - REGISTER(STOP, FALSE), - REGISTER(VOLUME, FALSE), - REGISTER(SHUFFLE, FALSE), - REGISTER(REPEAT, FALSE), - REGISTER(HIDE_PLAYER, FALSE), - REGISTER(TIME_UPDATES, FALSE), - REGISTER(FORMATTED_TIME, FALSE), - REGISTER(PLAYLIST_UPDATES, FALSE), - REGISTER(REQUEST, FALSE), - REGISTER(EXIT, TRUE), - REGISTER(QUIT, FALSE), - { "", NULL, FALSE } /* This must be the LAST line of the table */ -}; - -
--- a/Plugins/General/inetctl/inetctl_client.c Sun Feb 26 15:50:50 2006 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,227 +0,0 @@ -/* inetctl_client.c - client connection handler */ - -/* All code in here is related only to the client processing */ -/* done for a particular client session. Overall client */ -/* management is done in inetctl.c */ - -/* NOTE: All code running in this module is in the process */ -/* space of the child servicing a particular connection. It */ -/* does not have access to data in inetctl. */ - -#include "inetctl.h" - -/* Current client socket (for client handler) */ -int clientSocket = -1; -pid_t clientPID = -1; - -/* Buffers */ -#define TEXT_BUFFER_SIZE 1024 -#define READ_BUFFER_SIZE 32768 -char textBuffer[TEXT_BUFFER_SIZE]; -char readBuffer[READ_BUFFER_SIZE]; -int readBufferLength = 0; -int readBufferPtr = 0; - -/* Shuts us down. We don't return */ -void endThisClient() { - if (clientSocket != -1) { - close(clientSocket); - } - - kill(clientPID, SIGKILL); -} - -/* Read in next block of available bytes from client. If there */ -/* are no available bytes, block until there are. */ -int readBytesFromClient() { - int errval, bytesRead; - - struct pollfd clientWait; - clientWait.fd = clientSocket; - clientWait.events = POLLIN; - - /* sleep until events */ - SYSCALL(errval = poll(&clientWait, 1, -1)); - if (errval <= 0) return errval; - - /* Attempt to read as many bytes as are available */ - SYSCALL(bytesRead = read(clientSocket, readBuffer, READ_BUFFER_SIZE)); - switch(bytesRead) { - case 0: - writeDebug("Client closed connection\n"); - endThisClient(); - break; - - case -1: - writeDebug("Error when reading data from client - %s (%d)\n", strerror(errno), errno); - return 0; - break; - - default: - writeDebug("Read %d bytes from client\n", bytesRead); - break; - } - - /* Set # of bytes available and last byte used */ - readBufferLength = bytesRead; - readBufferPtr = 0; - return bytesRead; -} - -/* Read from client until we reach an EOL or an error. If */ -/* a line was read, return # of bytes (not including the */ -/* terminating null) in string. If there is an error, */ -/* return -1. bufferSize is the Max # of chars to write */ -/* into the passed client buffer */ -int readStringFromClient(String clientBuffer, int bufferSize) { - int charPtr = 0; - - for (;;) { - /* See if we need to fetch more bytes from the client */ - if (readBufferPtr == readBufferLength) { - if (readBytesFromClient() <= 0) return -1; - } - - /* See if this byte should be copied */ - if (readBuffer[readBufferPtr] == '\015') { - readBufferPtr++; - continue; - } - - /* See if this byte terminates the string */ - if (readBuffer[readBufferPtr] == '\012') { - readBufferPtr++; - clientBuffer[charPtr] = '\0'; - return charPtr; - } - - /* Copy over the character */ - clientBuffer[charPtr++] = readBuffer[readBufferPtr++]; - if (charPtr == bufferSize) return -2; - } - - /* Should never happen */ - return -3; -} - -/* Writes the passed # of bytes to client. if there is an */ -/* error, FALSE is returned. */ -Bool writeBytes(void *buffer, int byteCount) { - int bytesWritten; - - /* Attempt to write passed data to client */ - SYSCALL(bytesWritten = write(clientSocket, buffer, byteCount)); - if (bytesWritten != byteCount) return FALSE; - return TRUE; -} - -/* Write the passed null-terminated string */ -Bool writeText(String theFormat, ...) { - int bytesToWrite; - va_list theParms; - - /* Format the message */ - va_start(theParms, theFormat); - bytesToWrite = vsnprintf(textBuffer, TEXT_BUFFER_SIZE, theFormat, theParms); - va_end(theParms); - - /* See if there was an error */ - if (bytesToWrite <= 0) return FALSE; - - /* Format and print message */ - return writeBytes(textBuffer, bytesToWrite); -} - -/* Send a response code/message to the client */ -Bool sendResponse(String theResponseCode, String theResponse, ...) { - int bytesToWrite; - va_list theParms; - - /* Insure the response code is valid */ - if (theResponseCode == NULL) return FALSE; - if (strlen(theResponseCode) != 3) return FALSE; - - /* Install the response code */ - strcpy(textBuffer, theResponseCode); - strcat(textBuffer, " "); - - /* Format the message */ - va_start(theParms, theResponse); - bytesToWrite = vsnprintf(&textBuffer[4], TEXT_BUFFER_SIZE - 6, theResponse, theParms); - va_end(theParms); - - /* See if there was an error */ - if (bytesToWrite <= 0) return FALSE; - - /* Tack on standard line terminators */ - strcat(textBuffer, "\r\n"); - - /* Format and print message */ - return writeBytes(textBuffer, bytesToWrite + 6); -} - -/* Write initial client welcome message */ -Bool sendWelcome() { - char hostName[256]; - - /* Get host name */ - if (gethostname(hostName, 256) != 0) - strcpy(hostName, "unknown_host"); - - /* Write header out */ - return sendResponse("000", "%s XMMS_INETCTL server (Version %s) ready.", hostName, INETCTLVERSION); -} - -/* Read in client requests and dispatch as possible */ -void processClientRequests(pid_t theClientPID, int theClientSocket) { - int errval = 0; - char commandBuffer[1024]; - int bytesRead; - struct pollfd clientWait; - - /* Install specifics for this client */ - clientPID = theClientPID; - clientSocket = theClientSocket; - - /* Setup for polling */ - clientWait.fd = clientSocket; - clientWait.events = POLLIN; - - /* Welcome the client */ - if (!sendWelcome()) { - writeError("Client appears to be dead - stopping client handler\n"); - endThisClient(); - } - - /* Send current status */ - if (!sendNewClientStatus(theClientSocket)) { - writeError("Client appears to be dead - stopping client handler\n"); - endThisClient(); - } - - for(;;) { - /* Wait for something to come in from the client */ - if ((errval = poll(&clientWait, 1, 300)) < 0) { - writeDebug("Error polling client %s (%d) - terminating\n", strerror(errno), errno); - break; - } - - /* If this is a timeout, update stats on the clients connection */ - if (errval == 0) { - updatePlayerStatus(clientSocket); - continue; - } - - /* Read a string from the client */ - if ((bytesRead = readStringFromClient(commandBuffer, 1024)) == -1) { - writeError("Error trying to read from client - closing connection\n"); - return; - } - - /* Just in case we are watching */ - writeDebug("Read command from client [%s]\n", commandBuffer); - - /* Attempt to dispatch this command */ - dispatchCommand(commandBuffer); - } -}
--- a/Plugins/General/inetctl/inetctl_command.c Sun Feb 26 15:50:50 2006 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,265 +0,0 @@ -/* inetctl_command.c - Command parser and dispatcher */ - -/* Include commons */ -#include "inetctl.h" - -/* Private dynamic parse buffer */ -String parseBuffer = NULL; -int parseBufferSize = 0; - -/* Is the user authenticated? */ -String userName = NULL; -Bool userAuthenticated = FALSE; - -/* Private parameter store */ -#define MAX_PARMS 64 -String cmdParms[MAX_PARMS]; -int cmdParmCount = -1; - -/* upString will convert a string to upper case */ -void upString(String target) { - int charPtr = 0; - - /* Convert to upper case */ - while (target[charPtr] != '\0') { - /* See if we should convert */ - if ((target[charPtr] >= 'a') && (target[charPtr] <= 'z')) - target[charPtr] -= ('a' - 'A'); - charPtr++; - } -} - -/* trimString will trim leading/trailing spaces/tabs/new-lines */ -/* from a passed string. */ -void trimString(String theText) { - int srcPtr = 0, destPtr = 0; - - /* Skip empty strings */ - if (theText[0] == '\0') return; - - /* Strip trailing characters */ - destPtr = strlen(theText) - 1; - while (isspace(theText[destPtr])) theText[destPtr--] = '\0'; - - /* If the front part of string is okay, we're done */ - if (!isspace(theText[0])) return; - - /* Process each character */ - destPtr = 0; - while (theText[srcPtr] != '\0') { - /* See if we should skip this */ - if ((destPtr == 0) && isspace(theText[srcPtr])) - srcPtr++; - else - theText[destPtr++] = theText[srcPtr++]; - } - - /* Set terminator in place */ - theText[destPtr] = '\0'; -} - -/* Abrev will return TRUE if the passed string is a valid abreviation */ -/* of the passed string. You pass the string to test as 'source', the*/ -/* full command name as 'command' and the minimum # of chars that can */ -/* be matches as 'minchars'. If 'minchars' is passed as 0, then there*/ -/* can be no abreviation. The command must match exactly. If the */ -/* command is longer than the min # of chars, all chars after that */ -/* are checked as well. We stop when we hit the end of the line or */ -/* the chars don't match. */ -Bool abrevCheck(String source, String command, int minchars) { - int maxchar = strlen(source); - int maxmatch = strlen(command); - int charptr; - - /* Set the minimum # of chars if none specified */ - if (!minchars) minchars = maxmatch; - - /* Make sure we have at least as many characters as we need */ - /* and no more than we expected to handle */ - if ((maxchar < minchars) || (maxchar > maxmatch)) return FALSE; - - /* Test each character */ - for (charptr = 0; charptr < maxchar; charptr++) - /* If we fail to match, exit in shame */ - if (source[charptr] != command[charptr]) return FALSE; - - /* All our chars matched */ - return TRUE; -} - -/* ParseArgs will take a command and break it into a number of */ -/* arguments/tokens. 'command' is the command to process. 'argv'*/ -/* is the returned token list array. argc will be returned with */ -/* the # of args parsed. 'maxargs' is the max # of args that we */ -/* can deal with. If there are too many arguments or quoting is */ -/* goofed up or the command line is screwed up in any way, FALSE */ -/* is returned. Otherwise, TRUE. */ -Bool parseArgs(String command, String argv[], int *argc, int maxargs) { - int cmdLength = strlen(command); - char quoteChar = '\0'; - Bool quoteMode = FALSE; - Bool inParm = FALSE; - Bool quoteNextChar = FALSE; - String destChar; - int charPtr; - - /* Make sure we have enough room for a copy */ - if (parseBuffer == NULL) { - parseBufferSize = cmdLength + 1; - parseBuffer = (String) malloc(parseBufferSize); - writeDebug("Allocated %d bytes for parse buffer @ %p\n", parseBufferSize, parseBuffer); - } else if (cmdLength + 1 > parseBufferSize) { - parseBufferSize = cmdLength + 1; - parseBuffer = realloc(parseBuffer, parseBufferSize); - writeDebug("Expanded parse buffer to %d bytes @ %p\n", parseBufferSize, parseBuffer); - } - - /* Init for new parsing */ - *argc = 0; - destChar = parseBuffer; - - /* Run through each char, until we hit EOL */ - for (charPtr = 0; command[charPtr] != '\0'; charPtr++) { - /* See if we are dealing with a quoted character */ - if (!quoteNextChar) { - /* Copy everything in quote mode (or notice we're done quoting) */ - if (quoteMode) { - /* Check for End of Quote mode */ - if (command[charPtr] == quoteChar) { - *destChar++ = '\0'; - quoteMode = FALSE; - inParm = FALSE; - continue; - } - - /* Handle character quotes */ - if (command[charPtr] == '\\') { - quoteNextChar = TRUE; - continue; - } - - /* Anything else is copied verbatim */ - *destChar++ = command[charPtr]; - continue; - } - - /* See if we have a 'start of quote' flag */ - if (((command[charPtr] == '"') || (command[charPtr] == '\'')) && (!inParm)) { - /* Set quote mode */ - quoteChar = command[charPtr]; - quoteMode = TRUE; - - /* Start a new parm */ - if (*argc == maxargs) return FALSE; - argv[*argc] = destChar; - (*argc)++; - inParm = TRUE; - - continue; - } - - /* Handle spaces as terminators and/or junk */ - if (isspace(command[charPtr])) { - /* If we were in a parm, then end the parm here */ - if (inParm) { - *destChar++ = '\0'; - inParm = FALSE; - } - - continue; - } - } - - /* If we weren't in a parm on a regular char, start one */ - if (!inParm) { - inParm = TRUE; - - /* Start a new parm */ - if (*argc == maxargs) return FALSE; - argv[*argc] = destChar; - (*argc)++; - } - - /* Handle the character quoting character */ - if ((command[charPtr] == '\\' && !quoteNextChar)) { - quoteNextChar = TRUE; - continue; - } - - /* Copy a character over */ - *destChar++ = command[charPtr]; - quoteNextChar = FALSE; - } - - /* If we were in a parm, wrap things up */ - if (inParm) { - *destChar++ = '\0'; - inParm = FALSE; - } - - /* At EOL, make sure we are not in quote mode */ - return (!quoteMode); -} - -/* Take the passed command and parse it. Once parsed, */ -/* attempt to dispatch it to the appropriate handler. */ -/* If the command is processed correctly, TRUE is returned */ -/* and if there is an error (command not recognized, error */ -/* executing the command, etc). */ -Bool dispatchCommand(String theCommand) { - int commandIndex; - - /* Make sure we're not doomed */ - if (theCommand == NULL) return FALSE; - - /* Trim the string & exit on empty string or comment */ - trimString(theCommand); - if (theCommand[0] == '\0') return TRUE; - if (theCommand[0] == '#') return TRUE; - writeDebug("Begining dispatch on command [%s]\n", theCommand); - - /* Parse the command into parts */ - if (!parseArgs(theCommand, cmdParms, &cmdParmCount, MAX_PARMS)) { - sendResponse("002", "COMMAND FORMAT ERROR"); - return FALSE; - } - - /* Make sure the command isn't missing */ - if (cmdParmCount == 0) { - sendResponse("002", "MISSING COMMAND"); - return FALSE; - } - - /* Upcase the command and make sure we have one */ - trimString(cmdParms[0]); - upString(cmdParms[0]); - if (cmdParms[0][0] == '\0') { - sendResponse("002", "MISSING COMMAND"); - return FALSE; - } - - /* Try to find the command */ - for (commandIndex = 0; commandTable[commandIndex].commandFunc != NULL; commandIndex++) { - /* If command doesn't match, skip to next */ - if (strcmp(cmdParms[0], commandTable[commandIndex].commandName)) continue; - - /* If they are not authenticated and this command isn't always allowed, stop it */ - if (!userAuthenticated && !commandTable[commandIndex].alwaysAllowed) { - writeDebug("Attempt to execute %d before authentication - rejected\n", cmdParms[0]); - sendResponse("001", "NOT AUTHENTICATED"); - return FALSE; - } - - /* Dispatch to this command */ - writeDebug("Matched command %s - dispatching\n", commandTable[commandIndex].commandName); - if (commandTable[commandIndex].commandFunc(cmdParmCount, cmdParms)) { - sendResponse("005", theCommand); - return TRUE; - } else - return FALSE; - } - - /* If we get here, there was no match */ - sendResponse("002", "UNKNOWN COMMAND"); - return FALSE; -}
--- a/Plugins/General/inetctl/inetctl_config.c Sun Feb 26 15:50:50 2006 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,141 +0,0 @@ -/* inetctl_config.c - Configuration services */ - -#include "inetctl.h" - -/* U/I defines */ -GtkWidget *conf_dialog; -GtkObject *hour_w, *minute_w, *fadespeed_o; -GtkWidget *port_field; -gint hour, minute, fadespeed; -gchar *dummy; - - -void alert(gchar *message) { - GtkWidget *dialog, *label, *okay_button; - - /* Create the widgets */ - dialog = gtk_dialog_new(); - label = gtk_label_new (message); - okay_button = gtk_button_new_with_label("Okay"); - - /* Ensure that the dialog box is destroyed when the user clicks ok. */ - gtk_signal_connect_object (GTK_OBJECT (okay_button), "clicked", - GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT(dialog)); - gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area), - okay_button); - - /* Add the label, and show everything we've added to the dialog. */ - gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label); - gtk_widget_show_all (dialog); -} - -/* Write current configuration dialog values to config file */ -void write_config() { - ConfigDb *db = bmp_cfg_db_open(); - - /* Extract current values from U/I */ - listenPort = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(port_field)); - - /* Write values to config and close it */ - bmp_cfg_db_set_int(db, "inetctl", "port", listenPort); - bmp_cfg_db_close(db); -} - -/* Read values from config file and install. If no config file */ -/* then install sensible default values */ -void read_config() { - ConfigDb *db = bmp_cfg_db_open(); - bmp_cfg_db_get_int(db, "inetctl", "port", &listenPort); - bmp_cfg_db_close(db); -} - -void inetctl_config_ok (GtkWidget * wid, gpointer data) { - write_config(); - gtk_widget_destroy (conf_dialog); - conf_dialog = NULL; - return; -} - -void inetctl_config () { - GtkWidget *ok_button, *apply_button, *cancel_button; - GtkWidget *timebox, *port_w; - GtkWidget *bigbox, *buttonbox; - GtkWidget *timeframe; - - - if (conf_dialog) return; - - conf_dialog = gtk_window_new (GTK_WINDOW_TOPLEVEL); - - gtk_window_set_title (GTK_WINDOW (conf_dialog), ("iNetControl Configuration")); - gtk_window_set_policy (GTK_WINDOW (conf_dialog), FALSE, FALSE, FALSE); - gtk_window_set_position (GTK_WINDOW (conf_dialog), GTK_WIN_POS_MOUSE); - - gtk_container_set_border_width (GTK_CONTAINER (conf_dialog), 5); - - gtk_signal_connect (GTK_OBJECT (conf_dialog), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroyed), - &conf_dialog); - - bigbox = gtk_vbox_new (FALSE, 5); - gtk_container_add (GTK_CONTAINER (GTK_WINDOW (conf_dialog)), bigbox); - - timeframe = gtk_frame_new ("Server options:"); - gtk_container_add (GTK_CONTAINER (bigbox), timeframe); - - timebox = gtk_hbox_new (FALSE, 5); - gtk_container_set_border_width (GTK_CONTAINER (timebox), 5); - gtk_container_add (GTK_CONTAINER (timeframe), timebox); - - port_w = (GtkWidget *) gtk_adjustment_new (listenPort, 1, 256 * 256, 1, 1, 1); - port_field = gtk_spin_button_new (GTK_ADJUSTMENT (port_w), 1.0, 0); - - gtk_box_pack_start (GTK_BOX (timebox), gtk_label_new ("Port: "), FALSE, FALSE, 0); - gtk_box_pack_start (GTK_BOX (timebox), port_field, TRUE, TRUE, 0); - - buttonbox = gtk_hbutton_box_new (); - gtk_button_box_set_layout (GTK_BUTTON_BOX (buttonbox), GTK_BUTTONBOX_END); - gtk_button_box_set_spacing (GTK_BUTTON_BOX (buttonbox), 5); - gtk_box_pack_start (GTK_BOX (bigbox), buttonbox, FALSE, FALSE, 0); - - ok_button = gtk_button_new_with_label ("Ok"); - apply_button = gtk_button_new_with_label ("Apply"); - cancel_button = gtk_button_new_with_label ("Cancel"); - - gtk_signal_connect_object (GTK_OBJECT (cancel_button), "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy), - (gpointer) conf_dialog); - - gtk_signal_connect_object (GTK_OBJECT (apply_button), "clicked", GTK_SIGNAL_FUNC (write_config), NULL); - gtk_signal_connect_object (GTK_OBJECT (ok_button), "clicked", GTK_SIGNAL_FUNC (inetctl_config_ok), NULL); - - GTK_WIDGET_SET_FLAGS (ok_button, GTK_CAN_DEFAULT); - GTK_WIDGET_SET_FLAGS (cancel_button, GTK_CAN_DEFAULT); - GTK_WIDGET_SET_FLAGS (apply_button, GTK_CAN_DEFAULT); - - gtk_box_pack_start (GTK_BOX (buttonbox), ok_button, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (buttonbox), cancel_button, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (buttonbox), apply_button, TRUE, TRUE, 0); - - gtk_widget_show_all (conf_dialog); -} - -void inetctl_about () { - GtkWindow *about_box = (GtkWindow *) gtk_window_new(GTK_WINDOW_TOPLEVEL); - GtkVBox *container = (GtkVBox *) gtk_vbox_new(FALSE, 10); - GtkLabel *copyright = (GtkLabel *) gtk_label_new("(c) 2001 Gerry Duprey"); - GtkLabel *email = (GtkLabel *) gtk_label_new("gerry@cdp1802.org"); - GtkLabel *url = (GtkLabel *) gtk_label_new("http://www.cdp1802.org"); - - gtk_container_set_border_width(GTK_CONTAINER(container), 10); - gtk_window_set_title(about_box, "iNetControl"); - - gtk_container_add(GTK_CONTAINER(container), GTK_WIDGET(copyright)); - gtk_container_add(GTK_CONTAINER(container), GTK_WIDGET(email)); - gtk_container_add(GTK_CONTAINER(container), GTK_WIDGET(url)); - gtk_container_add(GTK_CONTAINER(about_box), GTK_WIDGET(container)); - - gtk_widget_show(GTK_WIDGET(copyright)); - gtk_widget_show(GTK_WIDGET(container)); - gtk_widget_show(GTK_WIDGET(url)); - gtk_widget_show(GTK_WIDGET(email)); - gtk_widget_show(GTK_WIDGET(about_box)); -}
--- a/Plugins/General/inetctl/inetctl_status.c Sun Feb 26 15:50:50 2006 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,346 +0,0 @@ -/* inetctl_status.c - status tracking and reporting module */ - -#include "inetctl.h" - -/* Static "previous state" of player */ -playerStatus lastPlayerStatus = { - .infoValid = FALSE, - .curTrackInPlaylist = 0, - .totalTracksInPlaylist = 0, - .curTrackLength = 0, - .curTrackTime = 0, - .trackTitle = {0, }, - .trackFile = {0, }, - .volume = 0, - .balance = 0, - .playing = FALSE, - .paused = FALSE, - .repeat = FALSE, - .shuffle = FALSE -}; - -/* Option/controls */ -Bool formattedTime = TRUE; -Bool timeStatusUpdates = TRUE; -Bool playlistUpdates = FALSE; - -/* Status buffer, used for formatting status messages */ -#define STATUS_BUFF_MAX 1024 -char statusBuffer[STATUS_BUFF_MAX]; - -/* Fill the passed player status structure with the players current status */ -Bool getPlayerStatus(playerStatusPtr theStatus) { - /* Playlist data */ - theStatus->curTrackInPlaylist = xmms_remote_get_playlist_pos(inetctl.xmms_session); - theStatus->totalTracksInPlaylist = xmms_remote_get_playlist_length(inetctl.xmms_session); - - /* Track data */ - theStatus->curTrackLength = xmms_remote_get_playlist_time(inetctl.xmms_session, theStatus->curTrackInPlaylist); - theStatus->curTrackTime = xmms_remote_get_output_time(inetctl.xmms_session); - strcpy(theStatus->trackTitle, xmms_remote_get_playlist_title(inetctl.xmms_session, theStatus->curTrackInPlaylist)); - strcpy(theStatus->trackFile, xmms_remote_get_playlist_file(inetctl.xmms_session, theStatus->curTrackInPlaylist)); - - /* Player data */ - theStatus->playing = xmms_remote_is_playing(inetctl.xmms_session); - theStatus->paused = xmms_remote_is_paused(inetctl.xmms_session); - theStatus->shuffle = xmms_remote_is_shuffle(inetctl.xmms_session); - theStatus->repeat = xmms_remote_is_repeat(inetctl.xmms_session); - theStatus->volume = xmms_remote_get_main_volume(inetctl.xmms_session); - theStatus->balance = xmms_remote_get_balance(inetctl.xmms_session); - - /* Mark valid and we are done */ - theStatus->infoValid = TRUE; - return TRUE; -} - -/* Set status of formatted times */ -void setFormattedTime(Bool doFormattedTime) { - formattedTime = doFormattedTime; -} - -/* Return TRUE if doing formatted time */ -Bool isFormattedTime() { - return formattedTime; -} - -/* Set status of time/progress updates */ -void setTimeUpdates(Bool doTimeUpdates) { - timeStatusUpdates = doTimeUpdates; -} - -/* Set status of playlist updates */ -void setPlaylistUpdates(Bool doPlaylistUpdates) { - playlistUpdates = doPlaylistUpdates; -} - -/* Write a quoted string out the the passed buffer */ -void writeQuotedString(String destBuffer, String theText) { - strcat(destBuffer, "\""); - strcat(destBuffer, theText); - strcat(destBuffer, "\""); -} - -/* Format a number into a string */ -void writeNumberString(String destBuffer, int theNumber) { - sprintf(destBuffer, "%d", theNumber); -} - -/* Format a passed # of seconds into a time */ -void writeTimeString(String destBuffer, int theTime) { - int hours, minutes, seconds; - - /* Handle unformatted times */ - if (!formattedTime) { - writeNumberString(destBuffer, theTime); - return; - } - - /* Decode into "english" time */ - theTime /= 1000; - hours = theTime / 3600; - minutes = (theTime % 3600) / 60; - seconds = theTime % 60; - - /* Format hours, if any */ - sprintf(destBuffer, "%d:%02d:%02d", hours, minutes, seconds); -} - -/* Initialize status tracking */ -Bool initStatusTracking() { - return getPlayerStatus(&lastPlayerStatus); -} - -/* Send track progress status */ -Bool sendTrackStatus(playerStatusPtr theStatus) { - /* Default the status, if needed */ - if (theStatus == NULL) theStatus = &lastPlayerStatus; - - /* Init the response buffer */ - statusBuffer[0] = '\0'; - - /* Format the info */ - writeTimeString(statusBuffer, theStatus->curTrackTime); - strcat(statusBuffer, " "); - writeTimeString(&statusBuffer[strlen(statusBuffer)], theStatus->curTrackLength); - - /* Send Status to client */ - return sendResponse("013", statusBuffer); -} - -/* Send playlist info */ -Bool sendPlaylistStatus(playerStatusPtr theStatus) { - /* Default the status, if needed */ - if (theStatus == NULL) theStatus = &lastPlayerStatus; - - /* Init the response buffer */ - statusBuffer[0] = '\0'; - - /* Format the info */ - writeNumberString(statusBuffer, theStatus->curTrackInPlaylist); - strcat(statusBuffer, " "); - writeNumberString(&statusBuffer[strlen(statusBuffer)], theStatus->totalTracksInPlaylist); - - /* Send Status to client */ - return sendResponse("012", statusBuffer); -} - -/* Send current playlist info */ -Bool sendPlaylistTracks(playerStatusPtr theStatus) { - int playListIndex; - - /* Default the status, if needed */ - if (theStatus == NULL) theStatus = &lastPlayerStatus; - - /* Send playlist header */ - strcpy(statusBuffer, "START "); - writeNumberString(&statusBuffer[strlen(statusBuffer)], theStatus->totalTracksInPlaylist); - strcat(statusBuffer, " "); - writeQuotedString(&statusBuffer[strlen(statusBuffer)], "Unknown"); /* Title */ - strcat(statusBuffer, " ");\ - writeQuotedString(&statusBuffer[strlen(statusBuffer)], "Unknown"); /* File path/name */ - if (!sendResponse("014", statusBuffer)) return FALSE; - - /* Iterate over all tracks in the playlist */ - for (playListIndex = 0; playListIndex < theStatus->totalTracksInPlaylist; playListIndex++) { - /* Format this tracks info */ - writeNumberString(statusBuffer, playListIndex); - strcat(statusBuffer, " "); - writeQuotedString(&statusBuffer[strlen(statusBuffer)], xmms_remote_get_playlist_title(inetctl.xmms_session, playListIndex)); - strcat(statusBuffer, " "); - writeQuotedString(&statusBuffer[strlen(statusBuffer)], xmms_remote_get_playlist_file(inetctl.xmms_session, playListIndex)); - strcat(statusBuffer, " "); - writeTimeString(&statusBuffer[strlen(statusBuffer)], xmms_remote_get_playlist_time(inetctl.xmms_session, playListIndex)); - if (!sendResponse("014", statusBuffer)) return FALSE; - } - - /* Write the terminator */ - strcpy(statusBuffer, "END "); - writeNumberString(&statusBuffer[strlen(statusBuffer)], theStatus->totalTracksInPlaylist); - return sendResponse("014", statusBuffer); -} - -/* Send info on current track */ -Bool sendTrackInfo(playerStatusPtr theStatus) { - int bitRate, sampleFreq, numChannels; - - /* Default the status, if needed */ - if (theStatus == NULL) theStatus = &lastPlayerStatus; - - /* Init the response buffer */ - statusBuffer[0] = '\0'; - - /* Format track data */ - writeQuotedString(statusBuffer, theStatus->trackTitle); - strcat(statusBuffer, " "); - writeQuotedString(&statusBuffer[strlen(statusBuffer)], theStatus->trackFile); - strcat(statusBuffer, " "); - writeTimeString(&statusBuffer[strlen(statusBuffer)], theStatus->curTrackLength); - - /* Format track stats */ - xmms_remote_get_info(inetctl.xmms_session, &bitRate, &sampleFreq, &numChannels); - strcat(statusBuffer, " "); - writeNumberString(&statusBuffer[strlen(statusBuffer)], bitRate); - strcat(statusBuffer, " "); - writeNumberString(&statusBuffer[strlen(statusBuffer)], sampleFreq); - strcat(statusBuffer, " "); - writeNumberString(&statusBuffer[strlen(statusBuffer)], numChannels); - - /* Send info to client */ - return sendResponse("011", statusBuffer); -} - -/* Format a player status message and dispatch it to the passed */ -/* client. If the passed client is -1, then all clients will */ -/* receive it. If the passed status pointer is NULL, the last */ -/* known players stats are used. */ -Bool sendPlayerStatus(playerStatusPtr theStatus) { - /* Default the status, if needed */ - if (theStatus == NULL) theStatus = &lastPlayerStatus; - - /* Init the response buffer */ - statusBuffer[0] = '\0'; - - /* Put in player state */ - if (theStatus->playing) { - if (theStatus->paused) - strcat(statusBuffer, "PAUSED"); - else - strcat(statusBuffer, "PLAYING"); - } else - strcat(statusBuffer, "STOPPED"); - - /* Put in volume */ - strcat(statusBuffer, " "); - writeNumberString(&statusBuffer[strlen(statusBuffer)], theStatus->volume); - - /* Put in shuffle mode flag */ - if (theStatus->shuffle) - strcat(statusBuffer, " SHUFFLE"); - else - strcat(statusBuffer, " NORMAL"); - - /* Put in repeat mode flag */ - if (theStatus->repeat) - strcat(statusBuffer, " REPEAT"); - else - strcat(statusBuffer, " SINGLE"); - - /* Send Status to client */ - return sendResponse("010", statusBuffer); -} - -/* Send new client status messages */ -Bool sendNewClientStatus(int clientSocket) { - /* Set initial status */ - initStatusTracking(); - - /* Now send each status */ - if (!sendPlayerStatus(NULL)) return FALSE; - if (!sendPlaylistStatus(NULL)) return FALSE; - if (!sendTrackInfo(NULL)) return FALSE; - if (!sendTrackStatus(NULL)) return FALSE; - - /* And we are done */ - return TRUE; -} - -/* Used by the clients to update their idea of the */ -/* players status */ -Bool freshenClientStatus() { - return !getPlayerStatus(&lastPlayerStatus); -} - -/* Check the player status. If anything has changed since we */ -/* last checked it's status, we issue an appropriate status */ -/* update to all connected clients */ -Bool updatePlayerStatus(int clientSocket) { - playerStatus curStatus; - Bool playerIsStopped = FALSE; - Bool statusChange = FALSE; - Bool playListChanged = FALSE; - Bool trackChanged = FALSE; - - /* Get player status */ - if (!getPlayerStatus(&curStatus)) return FALSE; - - /* See if the player is stopped */ - playerIsStopped = !curStatus.playing; - - /* See if we should create a 010 - player status change */ - if ((curStatus.playing != lastPlayerStatus.playing) - || (curStatus.paused != lastPlayerStatus.paused) - || (curStatus.volume != lastPlayerStatus.volume) - || (curStatus.balance != lastPlayerStatus.balance) - || (curStatus.repeat != lastPlayerStatus.repeat) - || (curStatus.shuffle != lastPlayerStatus.shuffle)) { - statusChange = TRUE; - writeDebug("Change in player status (010)\n"); - sendPlayerStatus(&curStatus); - } - - /* See if we should send 012 - playlist status change */ - if (((curStatus.curTrackInPlaylist != lastPlayerStatus.curTrackInPlaylist) - || (curStatus.totalTracksInPlaylist != lastPlayerStatus.totalTracksInPlaylist))) { - statusChange = TRUE; - playListChanged = TRUE; - writeDebug("Change in playlist status (012)\n"); - sendPlaylistStatus(&curStatus); - - /* If actual playlist changed (vs just our position), send that */ - if ((curStatus.totalTracksInPlaylist != lastPlayerStatus.totalTracksInPlaylist) && playlistUpdates) - sendPlaylistTracks(&curStatus); - } - - /* See if we should send a 011 - track info change */ - if (!playerIsStopped - && (playListChanged - || (curStatus.curTrackLength != lastPlayerStatus.curTrackLength) - || strcmp(curStatus.trackTitle, lastPlayerStatus.trackTitle) - || strcmp(curStatus.trackFile, lastPlayerStatus.trackFile))) { - statusChange = TRUE; - trackChanged = TRUE; - writeDebug("Change in track info (011)\n"); - sendTrackInfo(&curStatus); - } - - /* See if we should send a 013 - track status updates */ - if (!playerIsStopped - && timeStatusUpdates - && (playListChanged - || trackChanged - || (curStatus.curTrackLength != lastPlayerStatus.curTrackLength) - || (curStatus.curTrackTime != lastPlayerStatus.curTrackTime))) { - statusChange = TRUE; - writeDebug("Change in track status (013)\n"); - sendTrackStatus(&curStatus); - } - - /* If there was a change, copy it over */ - if (statusChange) { - memcpy(&lastPlayerStatus, &curStatus, sizeof(playerStatus)); - writeDebug("Copied off current status for later\n"); - } - - /* And we are done */ - return TRUE; -}