/*
 * command.h
 * Command* structures are used for argument marshalling in the home-grown
 * remote procedure calls between client and server.
 *
 * Copyright (C) Leni Mayo 2001-2002
 *
 *	This program is free software; you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License, version 2, as
 *	published by the Free Software Foundation.
 *	
 *	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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
/*
 * Overview
 *
 * Client programs send messages via a FIFO to the server.
 * The server responds by sending signals to the client.
 * 
 * Requests are modelled by the Command* structures.
 * In a typical usage, each Command* structure makes a request on behalf
 * of, or tells the server something about one of the service scripts.
 *
 * Command* structures are serialised into the Message structure for
 * transport through a FIFO to the server.
 * Command.pidReply    is the pid of the bgm client process
 * CommandRegister.pid is the pid of the service script.
 */

#ifndef _COMMAND_H_
#define _COMMAND_H_

#include <limits.h>
#include <unistd.h>  
#include "common.h"

/* user-defined signals sent by server to client
*/ 
#define SIG_RETURNSUCCESS  SIGUSR1
#define SIG_RETURNFAIL     SIGUSR2

typedef struct 
{
	CommandType c;
	Pid         pidReply; /* the pid of the client process, and target of signals sent by the server. */
} Command;

/*
 * If you think about including a path into this structure, think again -
 * On some systems, PATH_MAX might be roughly equivalent size to PIPE_BUF.
 */
typedef struct 
{
	Command      cmd;
	Pid          pid;   /* The pid of the process to which the command applies */
	ServiceName  name;
} CommandRegister;

typedef struct 
{
	Command   cmd;
	Pid       pid;
	PidStatus status;
} CommandStatusChange;

typedef struct 
{
	Command           cmd;
	ServerControlCode code;
} CommandServerControl;

typedef struct 
{
	Command     cmd;
	QueryCode   code;
	ServiceName name;
	PathName    fileChannel;
	PathName    fileAdd;     /* Used by query graph only */
	/* leni TODO: get rid of fileAdd by shoving it into the channel. */
} CommandQuery;

typedef struct 
{
	Command     cmd;
	ViaFileCode code;
	PathName    fileChannel; /* this tmp file contains the stdin of the command */
} CommandViaFile;

/*
 * Message is the structure that's written to the pipe.
 *
 * The total size of Message (in bytes) must be less than PIPE_BUF, in order
 * to retain atomicity guarantees.  In an environment of multiple writers,
 * messages of length >= PIPE_BUF are subject to interleaving.
 *
 * Message presents an interface of a stack of Commands.
 * Internally, Commands (and subclasses) are serialised to a
 * character array.  This makes for efficient multiplexing and
 * demultiplexing, without relying on some external library support
 * for collections and persistence.
 *
 * We also need the idea of atomicity to apply to a sequence of commands
 * from one client process that gets executed by the server w/o interleaving
 * of commands from another client process.
 * Message serves this purpose as well.
 *
 * Note that return signals from server to client are sent per-message,
 * not per-Command.
 *
 * leni - Thu Nov 22 23:15:59 EST 2001
 */
typedef struct 
{
	int cBytes;   /* number of bytes in buf containing meaningful data */
} MessageHeader;

typedef struct
{
	MessageHeader header;
	char buf[PIPE_BUF - sizeof(MessageHeader) - sizeof(int)];
} Message;

extern void commandInitialiseTables();
extern int  commandToCharStream(const Command *pSrc, char *pDst, int cDst);
extern void commandFromCharStream(Command *pDst, const char *pSrc, int cSrc);

extern void commandInitialise(Command *pCommand, CommandType type, Pid pid);

extern Command * commandDup(const Command *p);

extern void messageInitialise(Message *p);
extern void messagePush(Message *pMessage, const Command *pCommand);
extern Command * messagePopNew(Message *pMessage);

extern const char * commandAsString(const Command *p);
extern const char * commandTypeAsString(CommandType x);
extern const char * pidStatusAsString(PidStatus x);
extern const char * serverControlCodeAsString(ServerControlCode x);
extern const char * queryCodeAsString(QueryCode x);
extern const char * viaFileCodeAsString(ViaFileCode x);

extern CommandType commandTypeFromString(const char *psz);
extern RosterQueryCode rosterQueryCodeFromString(const char *psz);

#endif /* _COMMAND_H_ */
