/* -*-c-*- */
/*
* Fvwm command input interface.
*
* Copyright 1996, Toshi Isogai. No guarantees or warantees or anything
* are provided. Use this program at your own risk. Permission to use
* this program for any purpose is given,
* as long as the copyright is kept intact.
*/
/* 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
*/
/* FIXME: The signal handling of this module is largely broken */
#include "config.h"
#include "FvwmConsole.h"
#include "libs/fio.h"
#include "libs/fvwmsignal.h"
/* using ParseModuleArgs now */
static ModuleArgs* module;
int Fd[2]; /* pipe to fvwm */
int Ns = -1; /* socket handles */
char Name[80]; /* name of this program in executable format */
char *S_name = NULL; /* socket name */
void server(void);
RETSIGTYPE DeadPipe(int);
void ErrMsg(char *msg);
void SigHandler(int);
void clean_up(void)
{
if (Ns != -1)
{
close(Ns);
Ns = -1;
}
if (S_name != NULL)
{
unlink(S_name);
S_name = NULL;
}
return;
}
/*
* signal handler
*/
RETSIGTYPE DeadPipe(int dummy)
{
clean_up();
exit(0);
SIGNAL_RETURN;
}
RETSIGTYPE SigHandler(int dummy)
{
clean_up();
exit(0);
SIGNAL_RETURN;
}
RETSIGTYPE ReapChildren(int sig)
{
fvwmReapChildren(sig);
SIGNAL_RETURN;
}
int main(int argc, char *argv[])
{
char client[120];
char **eargv;
int i, j, k;
char *xterm_pre[] = { "-title", Name, "-name", Name, NULL };
char *xterm_post[] = { "-e", NULL, NULL };
int clpid;
/* Why is this not just put in the initializer of xterm_a?
* Apparently, it is a non-standard extension to use a non-constant
* address (of client) in an initializer (of xterm_a).
*/
xterm_post[1] = client;
module = ParseModuleArgs(argc, argv, 0); /* we don't use an alias */
if (module == NULL)
{
fprintf(
stderr, "FvwmConsole version "VERSION" should only be"
" executed by fvwm!\n");
exit(1);
}
strcpy(Name, module->name);
/* construct client's name */
strcpy(client, argv[0]);
strcat(client, "C");
eargv =(char **)safemalloc((argc+12)*sizeof(char *));
/* copy arguments */
eargv[0] = XTERM;
j = 1;
for (k = 0; xterm_pre[k] != NULL; j++, k++)
{
eargv[j] = xterm_pre[k];
}
for (i = 0; i< module->user_argc; i++)
{
if (!strcmp(module->user_argv[i], "-e"))
{
i++;
break;
}
else if (!strcmp(module->user_argv[i], "-terminal"))
{
i++;
if (i < module->user_argc)
/* use alternative terminal emulator */
eargv[0] = module->user_argv[i];
}
else
{
eargv[j++] = module->user_argv[i];
}
}
for (k = 0; xterm_post[k] != NULL; j++, k++)
{
eargv[j] = xterm_post[k];
}
/* copy rest of -e args */
for (; i<module->user_argc; i++, j++)
{
eargv[j-1] = module->user_argv[i];
}
eargv[j] = NULL;
signal(SIGCHLD, ReapChildren);
/* Dead pipes mean fvwm died */
signal(SIGPIPE, DeadPipe);
signal(SIGINT, SigHandler);
signal(SIGQUIT, SigHandler);
signal(SIGALRM, SigHandler);
Fd[0] = module->to_fvwm;
Fd[1] = module->from_fvwm;
/* launch xterm with client */
clpid = fork();
if (clpid < 0)
{
ErrMsg("client forking");
}
else if (clpid == 0)
{
execvp(*eargv, eargv);
ErrMsg("exec");
}
/* tell fvwm we're running */
SendFinishedStartupNotification(Fd);
server();
return 0;
}
/*
* setup server and communicate with fvwm and the client
*/
void server(void)
{
struct sockaddr_un sas, csas;
int len;
socklen_t clen; /* length of sockaddr */
char buf[MAX_COMMAND_SIZE]; /* command line buffer */
char *tline;
char ver[40];
fd_set fdset;
char *home;
int s;
int msglen;
int rc;
/* make a socket */
s = socket(AF_UNIX, SOCK_STREAM, 0);
if (s < 0 )
{
ErrMsg("socket");
}
/* name the socket */
home = getenv("FVWM_USERDIR");
S_name = safemalloc(strlen(home) + sizeof(S_NAME) + 1);
strcpy(S_name, home);
strcat(S_name, S_NAME);
sas.sun_family = AF_UNIX;
strcpy(sas.sun_path, S_name);
/* bind the above name to the socket: first, erase the old socket */
unlink(S_name);
len = sizeof(sas) - sizeof(sas.sun_path) + strlen(sas.sun_path);
umask(0077);
rc = bind(s, (struct sockaddr *)&sas, len);
if (rc < 0)
{
ErrMsg("bind");
}
else
{
/* don't wait forever for connections */
alarm(FVWMCONSOLE_CONNECTION_TO_SECS);
/* listen to the socket */
rc = listen(s, 5);
alarm(0);
if (rc < 0)
{
ErrMsg("listen");
}
/* accept connections */
clen = sizeof(csas);
Ns = accept(s, (struct sockaddr *)&csas, &clen);
if (Ns < 0)
{
ErrMsg("accept");
}
}
/* send config lines to Client */
tline = NULL;
fvwm_send(Ns, C_BEG, strlen(C_BEG), 0);
GetConfigLine(Fd, &tline);
while (tline != NULL)
{
if (strlen(tline) > 1)
{
fvwm_send(Ns, tline, strlen(tline), 0);
fvwm_send(Ns, "\n", 1, 0);
}
GetConfigLine(Fd, &tline);
}
fvwm_send(Ns, C_END, strlen(C_END), 0);
strcpy(ver, "*");
strcpy(ver, module->name);
strcat(ver, " version ");
strcat(ver, VERSION VERSIONINFO);
strcat(ver, "\n");
fvwm_send(Ns, ver, strlen(ver), 0);
while (1)
{
FD_ZERO(&fdset);
FD_SET(Ns, &fdset);
FD_SET(Fd[1], &fdset);
fvwmSelect(FD_SETSIZE, SELECT_FD_SET_CAST &fdset, 0, 0, NULL);
if (FD_ISSET(Fd[1], &fdset))
{
FvwmPacket* packet = ReadFvwmPacket(Fd[1]);
if (packet == NULL)
{
clean_up();
exit(0);
}
else
{
if (packet->type == M_PASS)
{
msglen = strlen(
(char *)&(packet->body[3]));
if (msglen > MAX_MESSAGE_SIZE-2)
{
msglen = MAX_MESSAGE_SIZE-2;
}
fvwm_send(
Ns, (char *)&(packet->body[3]),
msglen, 0);
}
}
}
if (FD_ISSET(Ns, &fdset))
{
int len;
int rc;
rc = fvwm_recv(Ns, buf, MAX_COMMAND_SIZE, 0);
if (rc == 0)
{
/* client is terminated */
clean_up();
exit(0);
}
/* process the own unique commands */
len = strlen(buf);
if (len > 0 && buf[len - 1] == '\n')
{
buf[len - 1] = '\0';
}
/* send command */
SendText(Fd, buf, 0);
}
}
}
/*
* print error message on stderr and exit
*/
void ErrMsg(char *msg)
{
fprintf(
stderr, "%s server error in %s, errno %d: %s\n", Name, msg,
errno, strerror(errno));
clean_up();
exit(1);
}
syntax highlighted by Code2HTML, v. 0.9.1