/* agent.c This file is part of "Pharmacy: A GNOME CVS front-end" Copyright 1998 Reklaw (N. Adam Walker) "Pharmacy" is released under the GPL See the LICENCE for more details. */ #include "config.h" #include #include "utils.h" #include #include #include #include #include #include "agent.h" #define BUFFER_SIZE 4097 static GtkObjectClass *parent_class = NULL; static void agent_class_init (AgentClass * klass); static void agent_destroy (GtkObject * object); static void agent_init (Agent * object); static void read_child_output_cb (Agent * agent, gchar * str, gint len); static void agent_stream_cb (Agent * agent, gchar * str, gint len); static void read_child_error_cb (Agent * agent, gchar * str, gint len); static void child_died_cb (Agent * agent); static void agent_class_init (AgentClass * klass) { GtkObjectClass *objectclass = GTK_OBJECT_CLASS (klass); gint signals[4]; objectclass->destroy = agent_destroy; signals[0] = gtk_signal_new (AGENT_READ_CHILD_OUTPUT_SIGNAL, GTK_RUN_FIRST, objectclass->type, GTK_SIGNAL_OFFSET (AgentClass, read_child_output), gtk_marshal_NONE__POINTER_INT, GTK_TYPE_NONE, 2, GTK_TYPE_POINTER, GTK_TYPE_INT); signals[1] = gtk_signal_new (AGENT_READ_CHILD_ERROR_SIGNAL, GTK_RUN_FIRST, objectclass->type, GTK_SIGNAL_OFFSET (AgentClass, read_child_error), gtk_marshal_NONE__POINTER_INT, GTK_TYPE_NONE, 2, GTK_TYPE_POINTER, GTK_TYPE_INT); signals[2] = gtk_signal_new (AGENT_CHILD_DIED_SIGNAL, GTK_RUN_LAST, objectclass->type, GTK_SIGNAL_OFFSET (AgentClass, child_died), gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); signals[3] = gtk_signal_new (AGENT_STREAM_SIGNAL, GTK_RUN_FIRST, objectclass->type, GTK_SIGNAL_OFFSET (AgentClass, agent_stream), gtk_marshal_NONE__POINTER_INT, GTK_TYPE_NONE, 2, GTK_TYPE_POINTER, GTK_TYPE_INT); gtk_object_class_add_signals (objectclass, signals, 4); klass->read_child_output = read_child_output_cb; klass->read_child_error = read_child_error_cb; klass->child_died = child_died_cb; klass->agent_stream = agent_stream_cb; } GtkObject * agent_new () { GtkObject *retval = NULL; Agent *obj = NULL; retval = gtk_type_new (agent_get_type ()); obj = AGENT (retval); return retval; } guint agent_get_type () { static guint type = 0; if (!type) { GtkTypeInfo info = { "Agent", sizeof (Agent), sizeof (AgentClass), (GtkClassInitFunc) agent_class_init, (GtkObjectInitFunc) agent_init, (GtkArgSetFunc) NULL, (GtkArgGetFunc) NULL }; type = gtk_type_unique (gtk_object_get_type (), &info); parent_class = gtk_type_class (gtk_object_get_type ()); } return type; } static void agent_init (Agent * object) { g_assert(object && IS_AGENT(object)); object->childpid = -1; object->childfd = -1; object->msgfd = -1; object->input_id = -1; object->msg_id = -1; } static void agent_destroy (GtkObject * object) { Agent *pAgent = AGENT (object); g_assert(object && IS_AGENT(object)); /* whatever */ } static void read_child_output_cb (Agent * agent, gchar * str, gint len) { } static void agent_stream_cb (Agent * agent, gchar * str, gint len) { } static void read_child_error_cb (Agent * agent, gchar * str, gint len) { } static void child_died_cb (Agent * agent) { } static void agent_excute_child (Agent * agent, gchar * cmd) { gchar *exec_cmd = NULL; g_assert(agent && IS_AGENT(agent)); g_assert(cmd); g_debug_message2 ("About to run: %s", cmd); exec_cmd = cmd; execl ("/bin/sh", "sh", "-c", exec_cmd, (char *) 0); g_error ("execl failed: sh"); _exit (-1); } static void agent_readdata (gpointer data, gint fd, GdkInputCondition condition) { gchar buffer[BUFFER_SIZE]; int count; int saveerrno; Agent *agent = AGENT (data); g_assert(IS_AGENT(data)); if (agent->childfd != -1) { saveerrno = EAGAIN; memset (buffer, 0, sizeof (buffer)); while ((saveerrno == EAGAIN) && ((count = read (fd, buffer, BUFFER_SIZE - 1)) > 0)) { saveerrno = errno; /* send signal */ gtk_signal_emit_by_name (GTK_OBJECT (agent), AGENT_READ_CHILD_OUTPUT_SIGNAL, buffer, count); gdk_flush (); } } } static void agent_readmsg (gpointer data, gint fd, GdkInputCondition condition) { Agent *pAgent = AGENT (data); g_assert(IS_AGENT(data)); gdk_flush (); agent_readdata(data,pAgent->childfd,condition); agent_closepty (pAgent); gdk_flush (); if (pAgent->input_id != -1) { gdk_input_remove (pAgent->input_id); pAgent->input_id = -1; } gtk_signal_emit_by_name (GTK_OBJECT (pAgent), AGENT_CHILD_DIED_SIGNAL); } /* Agent::Run setup comunication between the parent and a newly created child process. */ void agent_run (Agent * agent, gchar * cmd) { char ttyname[256]; int pid; gchar* msg = NULL; g_assert(agent && IS_AGENT(agent)); g_assert(cmd); /* Display cmd */ msg = g_strconcat(cmd,"\r\n",NULL); gtk_signal_emit_by_name (GTK_OBJECT (agent), AGENT_STREAM_SIGNAL, msg, strlen(msg)+1); g_free(msg); msg = NULL; gdk_flush(); pid = init_subshell (&agent->childfd, ttyname, &agent->msgfd); if (pid > 0) { agent->childpid = pid; fcntl (agent->childfd, F_SETFL, O_NONBLOCK); agent->input_id = gdk_input_add (agent->childfd, GDK_INPUT_READ, agent_readdata, agent); agent->msg_id = gdk_input_add (agent->msgfd, GDK_INPUT_READ, agent_readmsg, agent); } else { if (pid == 0) { agent_excute_child (agent, cmd); } } } int agent_closepty (Agent * agent) { gint nRet = 0; g_return_val_if_fail (agent != NULL, -1); g_return_val_if_fail (IS_AGENT (agent), -1); gdk_flush(); if (agent->input_id != -1) { gdk_input_remove (agent->input_id); agent->input_id = -1; } if (agent->msg_id != -1) { gdk_input_remove (agent->msg_id); agent->msg_id = -1; } if (agent->childfd != -1) { nRet = close (agent->childfd); close (agent->msgfd); agent->msgfd = agent->childfd = -1; } return nRet; } int agent_abort (Agent * agent) { gint nRet = -1; g_assert(agent && IS_AGENT(agent)); if (agent_in_use (agent)) { nRet = kill (agent->childpid, 15); } return nRet; } int agent_writechild (Agent * agent, gchar * buffer, gint len) { g_assert(agent && IS_AGENT(agent)); g_assert(buffer && len); return write (agent->childfd, buffer, len); } int agent_readchild (Agent * agent, gchar * buffer, gint len) { g_assert(agent && IS_AGENT(agent)); g_assert(buffer && len); return read (agent->childfd, buffer, len); } gchar * concat_to_buffer (gchar ** pBuffer, gchar * str) { gchar *pTemp = NULL; if (pBuffer) { if ((*pBuffer)) { pTemp = g_strconcat ((*pBuffer), str, NULL); g_free (*pBuffer); (*pBuffer) = pTemp; } else { (*pBuffer) = pTemp = g_strdup (str); } } return pTemp; } gint agent_in_use (Agent * pAgent) { g_assert(pAgent && IS_AGENT(pAgent)); return pAgent->childfd != -1; }