/*
* use_ipc.c -- interface to the inter-process communication
*
* PMF -- Padrone's MudFrontend, a frontend for (maybe mostly LP-)mud
* Thomas Padron-McCarthy (Email: padrone@lysator.liu.se), 1990, 1991
* Share and enjoy, but be nice: don't steal my program! Hugo is watching!
* This file latest updated: May 23, 1993
*
*/
#include <strings.h>
#include <stdio.h>
#include <sys/param.h>
#include <ctype.h>
#include "safe_malloc.h"
#include "str_galore.h"
#include "pmf.h"
#include "config.h"
#include "globals.h"
#define ELEMENT_POINTER_TYPE struct queue_to_mud_entry *
#include "generic_list.h"
#include "generic_fifo.h"
static generic_fifo queue_to_mud = NULL;
static generic_list express_list = NULL;
struct queue_to_mud_entry {
char *line_to_send, *confirm_string;
};
static int waiting_for_response;
extern char *get_line_from_mud(), *cryptsay_handle_line();
extern char compile_time[], version[];
/*---------------------------------------------------------------------------*/
init_queue_to_mud()
{
queue_to_mud = create_generic_fifo();
set_generic_fifo_increment(queue_to_mud, QUEUE_TO_MUD_INCREMENT);
express_list = create_generic_list();
set_generic_list_increment(express_list, EXPRESS_LIST_INCREMENT);
} /* init_queue_to_mud */
struct queue_to_mud_entry *create_queue_entry(line_to_send, confirm_string)
char *line_to_send, *confirm_string;
{
struct queue_to_mud_entry *this_queue_entry;
this_queue_entry = (struct queue_to_mud_entry *)
safe_malloc(sizeof(struct queue_to_mud_entry));
this_queue_entry->line_to_send = copy_string(line_to_send);
if (confirm_string)
this_queue_entry->confirm_string = copy_string(confirm_string);
else
this_queue_entry->confirm_string = NULL;
return this_queue_entry;
} /* create_queue_entry */
/* Put a line on the queue of lines to be sent to the game.
* confirm_string is the string we will wait for as a confirmation from
* the game that it has received the line sent. If no confirm_string is NULL,
* we will not wait for confirmation.
* An empty string means accept any output from the mud game as confirmation.
*/
queue_mudline(line_to_send, confirm_string)
char *line_to_send, *confirm_string;
{
struct queue_to_mud_entry *this_queue_entry;
ASSERT(line_to_send);
USER_DEBUG(("Queueing: \"%s\", \"%s\"\n", line_to_send, confirm_string ? confirm_string : "NULL"));
this_queue_entry = create_queue_entry(line_to_send, confirm_string);
queue_on_generic_fifo(queue_to_mud, this_queue_entry);
} /* queue_mudline */
/* Put a line on the express list, to be put first in the queue later.
* If we put the lines first in the queue directly, they would be sent
* in reverse order, so we must use an extra list.
*/
express_queue_mudline(line_to_send, confirm_string)
char *line_to_send, *confirm_string;
{
struct queue_to_mud_entry *this_queue_entry;
ASSERT(line_to_send);
USER_DEBUG(("To express list: \"%s\", \"%s\"\n", line_to_send, confirm_string ? confirm_string : "NULL"));
this_queue_entry = create_queue_entry(line_to_send, confirm_string);
add_last_to_generic_list(express_list, this_queue_entry);
} /* express_queue_mudline */
/* Take the lines from the express list and put them first in the queue to MUD: */
flush_express_list()
{
struct queue_to_mud_entry *this_queue_entry;
while ((this_queue_entry = remove_last_from_generic_list(express_list)) != NULL) {
USER_DEBUG(("Express-queueing from express list: \"%s\", \"%s\"\n",
this_queue_entry->line_to_send,
this_queue_entry->confirm_string ? this_queue_entry->confirm_string : "NULL"));
add_first_to_generic_list(get_list_inside_generic_fifo(queue_to_mud),
this_queue_entry);
}
} /* flush_express_list */
/* This function checks if the (probably just received) line_from_mud
* matches the (probably the current, global) confirm_string.
* Returns 1 or 0.
*/
int match_confirm_string(line_from_mud, confirm_string, confirm_string_length)
char *line_from_mud, *confirm_string;
int confirm_string_length;
{
/* The words returned by dollar_match are never used. */
char *mudline_words[MAX_WORDS_PER_LINE];
char mudline_words_buffer[2 * MAX_LINE_LENGTH];
INTERNAL_DEBUG(("match_confirm_string('%s', '%s', %d)",
line_from_mud, confirm_string, confirm_string_length));
return (!strncmp(confirm_string, line_from_mud, confirm_string_length))
|| (dollar_match(confirm_string, line_from_mud,
mudline_words, mudline_words_buffer) != -1);
} /* match_confirm_string */
/* This function should be called periodically (at least a few times each
* second). It takes care of all the communication with the mud process.
* Never do any read or write calls or any other operations on the socket
* except from this function! Returns 0 if nothing happened.
* Also, if nothing happened we sleep for a while.
*/
int communicate_with_mud()
{
struct queue_to_mud_entry *to_head;
char *line_from_mud, *line_to_mud;
/* These variables are used to save the state between calls: */
/* static int waiting_for_response = 0; -- moved outside! */
static char confirm_string[MAX_CONFIRM_STRING_LENGTH + 1];
static int confirm_string_length;
int retval, was_gag;
char *nl_p;
#ifdef GNU_READLINE
readline_prompt[0] = readline_prompt_first_char;
#endif
retval = 0;
line_from_mud = get_line_from_mud();
/* It is possible that the "line_from_mud" is just a part of a line. */
if (line_from_mud) {
USER_DEBUG(("communicate_with_mud: got a line: \"%s\"", line_from_mud));
if ( waiting_for_response
&& match_confirm_string(line_from_mud, confirm_string, confirm_string_length)) {
USER_DEBUG(("communicate_with_mud: got confirm_string \"%s\" in line \"%s\"", confirm_string, line_from_mud));
waiting_for_response = 0;
}
/* We use the telnet codes too, but do this kludge too: */
if (!strcmp(line_from_mud, "Password: "))
echo_off();
IPC_DEBUG(("line = \"%s\", strcmp(line, \"Password: \") = %d",
line_from_mud, strcmp(line_from_mud, "Password: ")));
if (receiving) {
if (match_confirm_string(line_from_mud, receive_stop_string, strlen(receive_stop_string))) {
USER_DEBUG(("communicate_with_mud: got receive_stop_string \"%s\" in line \"%s\"",
receive_stop_string, line_from_mud));
stop_receiving();
}
else {
fprintf(the_open_file, "%s", line_from_mud);
}
}
/* If doing a "getfile": save the text, newlines NOT stripped! */
if (getfiling)
getfile_got_text(line_from_mud);
/* Is there a newline character at the end of the line? Remove it! */
nl_p = &line_from_mud[strlen(line_from_mud) - 1];
if (*nl_p == '\n') {
*nl_p = '\0';
++nr_received_lines;
}
else
nl_p = NULL;
/* Checking for gagging: newlines stripped! */
was_gag = is_gag_line(line_from_mud)
&& (can_gag_fight || !fighting_line(line_from_mud));
/* The secret stuff! */
if (cryptkey) {
char *temp;
temp = cryptsay_handle_line(line_from_mud);
/* safe_free(line_from_mud); -- this is done in cryptsay_handle_line! */
line_from_mud = temp;
}
if ((getfiling || receiving) && !show_receive) {
if (nl_p) {
/* Lars has no line buffering on the sockets, even when inside ed. */
ldisplay(".");
fflush(stdout);
}
}
else if (!was_gag) {
rdisplay("%s", line_from_mud); /* The line can contain %'s! */
if (nl_p)
rdisplay("\n");
}
retval += 1;
/* You can remove these three automatic actions,
* but try to avoid doing that.
* At least keep the version query! /Padrone
*/
/* Very hard-coded: if PMF_QUERY_VERSION is sent, we reply! */
if (!strcmp(line_from_mud, "PMF_QUERY_VERSION")) {
char buf[MAX_LINE_LENGTH + 1];
sprintf(buf, "say pmf version \"%s\" compiled %s\n",
version, compile_time);
message("Your PMF just answered a PMF_QUERY_VERSION message.");
queue_mudline(buf, "");
}
/* And another one: if PMF_QUERY_HOST is sent, we reply! */
if (!strcmp(line_from_mud, "PMF_QUERY_HOST")) {
char namebuf[MAXHOSTNAMELEN + 1], buf[MAX_LINE_LENGTH + 1];
extern char *gethostname();
if (gethostname(namebuf, MAXHOSTNAMELEN) == 0)
sprintf(buf, "say host name \"%s\"\n", namebuf);
else
sprintf(buf, "say host name unknown\n");
message("Your PMF just answered a PMF_QUERY_HOST message.");
queue_mudline(buf, "");
}
/* And another one: if PMF_QUERY_TERM is sent, we reply! */
if (!strcmp(line_from_mud, "PMF_QUERY_TERM")) {
char *termtype, buf[MAX_LINE_LENGTH + 1];
extern char *getenv();
termtype = getenv("TERM");
if (termtype)
sprintf(buf, "say terminal type \"%s\"\n", termtype);
else
sprintf(buf, "say terminal type unknown\n");
message("Your PMF just answered a PMF_QUERY_TERM message.");
queue_mudline(buf, "");
}
if (robot_mode && !sending && !receiving && !getfiling && !was_gag) {
robot_handle_line(line_from_mud);
}
#ifdef SOUND
if (sound_mode && !sending && !receiving && !getfiling && !was_gag) {
sound_handle_line(line_from_mud);
}
#endif
}
if (!waiting_for_response) {
to_head = (struct queue_to_mud_entry *)get_from_generic_fifo(queue_to_mud);
if (to_head) {
USER_DEBUG(("Got from queue: \"%s\", \"%s\"\n", to_head->line_to_send, to_head->confirm_string ? to_head->confirm_string : "NULL"));
line_to_mud = to_head->line_to_send;
if (to_head->confirm_string) {
confirm_string_length = strlen(to_head->confirm_string);
if (confirm_string_length > MAX_CONFIRM_STRING_LENGTH)
error("Ridicolously long confirmation string (%d chars): \"%s\".",
confirm_string_length, confirm_string);
strcpy(confirm_string, to_head->confirm_string);
waiting_for_response = 1;
USER_DEBUG(("communicate_with_mud: confirm_string set to \"%s\"", confirm_string));
}
safe_free(to_head);
if (line_to_mud) {
USER_DEBUG(("communicate_with_mud: sending line \"%s\"", line_to_mud));
send_to_mud(line_to_mud);
safe_free(line_to_mud);
}
else {
USER_DEBUG(("communicate_with_mud: line was null, not sending"));
}
retval += 2;
}
}
if (!retval)
usleep(100000);
/*
#ifdef GNU_READLINE
else
pmf_rl_redisplay_line(1, 0);
#endif
*/
return retval;
} /* communicate_with_mud */
int ok_to_send()
{
return query_generic_fifo_size(queue_to_mud) == 0 && !waiting_for_response;
} /* ok_to_send */
int query_queue_to_mud_size()
{
return query_generic_fifo_size(queue_to_mud);
} /* query_queue_to_mud_size */
void flush_queue_to_mud()
{
struct queue_to_mud_entry *to_head;
int i;
to_head = (struct queue_to_mud_entry *)get_from_generic_fifo(queue_to_mud);
if (to_head) {
ldisplay("Throwing away the lines on the queue to MUD:\n");
i = 0;
while (to_head) {
++i;
ldisplay(" %d:\t%s\n", i, to_head->line_to_send);
to_head = (struct queue_to_mud_entry *)get_from_generic_fifo(queue_to_mud);
}
}
waiting_for_response = 0;
} /* flush_queue_to_mud */
int query_waiting_for_response()
{
return waiting_for_response;
} /* query_waiting_for_response */
syntax highlighted by Code2HTML, v. 0.9.1