Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

TINTIN - a dikumud client

85 views
Skip to first unread message

Peter Joachim Unold

unread,
Apr 1, 1992, 9:15:33 AM4/1/92
to

T I N T I N

(T)he K(I)cki(N) (T)ick D(I)kumud Clie(N)t
(hell I simply wanted it to be called TINTIN....)

This client is more or less a byproduct from a robot-player prog I'm coding
at the moment. This means that the prog. don't has the same amount of features
that progs like PMF and tinymugys have(weird features that you don't use
anyway...). The prog has however some features special designed to diku-mud
that might make it interesting for you. The prog is UNIX only..

The prog is started like this:
tintin mud-address port-number

If you discover any bugs, have any probs with the prog or have sugestions for
new tintin-commands then lemmie hear -

email: pju...@daimi.aau.dk or on MUDs Tintin/Snowy/Socrates/Zork/Deep etc...

TINTIN's commands:

One feature that is common for all commands is that they can be seperated with
a ';'. This can often be useful. Suppose you want to go north, look at green
dragon and go south, you would normally type:
>n
>l green
>s
with TINTIN running you could have typed:
>n;l green;s
and thereby providing a faster(and safer) check of green's condition.

--------------------------------------
Command: repeat
usage: #number command

This way you can repeat a command. You cannot repeat a command more than 20
times.
Example:
#10 buy bread <=but 10 breads

--------------------------------------
Command: alias
Usage: #alias [aliased-command[=[unaliases-command(s)]]]

If there is a '&' somewhere in the unaliased-commands, this '&' will be
replaced with the text typed after the aliased-command when the alias is
executed. If no text follows the aliased-command, a space will replace the
'&'s.
Examples:
#alias eb=get bread bag;eat bread <=define alias
#alias eb <=show alias
#alias eb= <=delete alias
#alias <=list all aliases
#alias ff=cast 'fireball' &
#alias pissoff=say PISSOF &!!!! OR I GONNA FIREBALL YOUR ASS!;wink &

---------------------------------------
Command: action
Usage: #action [action-text[=[action-command(s)]]]

Use this command to define an action to take place when a particular text
appears on your screen. The FIRST word in an action-text can be variable.
This variable can then be used in the action that takes place, just like the
'&' operator for the alias-command.
Example:
#action You are hungry.=eat bread <=eat bread automatic when hungry.
#action You are hungry. <=show action
#action You are hungry.= <=delete action
#action <=list all actions
#action & has arrived.=pat &;tell & hi <=greet everybody that enters room

----------------------------------------
Command: readcoms
Usage: #readcoms filename

readcoms reads a textfile containing alias and action commands.

----------------------------------------
Command: tickon
Usage: #tickon

tickon turns the tick-counter on and resets it. The tick-counter is a
counter that tells you when the next tick occures. That is it'll warn
you just before the next tick. Tick occures every 75 second. This is
however not quite stable, so use the action command to keep the
counter updated with the MUD's tick... ie:
#action You are hungry.=(some eating stuff);#tickon
#action Thew sun rises in the east.=#tickon

----------------------------------------
Command: tickoff
Usage: #tickoff

tickoff turns the tick-counter off.

----------------------------------------
Command: tick
Usage: #tick

tick tells you # seconds to next tick.

----------------------------------------
Command: ticktell
Usage: #ticktell player-name

With ticktell you can tell a player how long there's to next tick.
ticktell was coded to provide an easy way to tell other players the time.
Especially you can make an action so players not having a tickcounter can
get the time easily.
Example:
#action & tells you 'tick'.=#ticktell &

----------------------------------------

/* T I N T I N v1.0
* (T)he K(I)cki(N) (T)ick D(I)kumud Clie(N)t
* Coded by Peter Unold 1992
* email: pju...@daimi.aau.dk
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <ctype.h>

#define ALIASROOM 30
#define ACTIONROOM 30

/******** PROTOTYPES FOR FUNCTIONS **********/
void runtintin(void);
void syserr(char *msg);
void read_coms(char *filename);
void parseinput(char *command, char *arg);
void infofd(int fd);
void tickon();
void tickoff();
void getuserinput();
static void tickfunc();
static void myquitsig();
void parse_input(char *command);
void parse_tintin(char *command, char *arg);
void substitute_alias(char *cpsource, char *cpdest, char *cpsubtext);
int search_alias(char *cptr);
char *space_out(char *cptr);
void check_action();
void gettelnetoutput();
void parse_alias(char *cptr);
void parse_action(char *cptr);
void show_aliases();
void show_actions();

char inputline[50];

char aliasleft[ALIASROOM][20];
char aliasright[ALIASROOM][100];
int aliasno=0;

char actionleft[ACTIONROOM][100];
char actionright[ACTIONROOM][100];
int actionno=0;

int pfdto[2],pfdfrom[2];

char buffer[512], linebuffer[512];
char *cpbufferdest=linebuffer;
char *netaddress, *portnumber;

long time0;
int sec_to_tick,tickswitch=0;

int main(int argc, char *argv[])
{
if(argc!=3) {
fprintf(stderr,"USAGE: tintin mudaddress portnumber\n");
exit(1);
}

netaddress=argv[1];
portnumber=argv[2];
runtintin();

return(0);
}

/**********************************/
/* child process - calling telnet */
/**********************************/
mychild()
{
if(close(1)==-1)
syserr("close0");
if(dup(pfdfrom[1])!=1)
syserr("dup");
if(close(pfdfrom[0])==-1 || close(pfdfrom[1])==-1)
syserr("close");
if(close(0)==-1)
syserr("close1");
if(dup(pfdto[0])!=0)
syserr("dup");
if(close(pfdto[0])==-1 || close(pfdto[1])==-1)
syserr("close2");
execlp("telnet","telnet",netaddress,portnumber,NULL);
syserr("execl");
}

/**********************************************************/
/* main function. stays in it until a signal get's it out */
/**********************************************************/
void runtintin(void)
{
int i,flag,inputlinelen,dun=0;
char inputline[80],*argptr,linebuffer[512];
char *cptr,*cptrs,*cptrd;

if(pipe(pfdto)==-1)
syserr("pipe");
if(pipe(pfdfrom)==-1)
syserr("pipe");

switch(fork()) {
case -1:
syserr("fork");
case 0:
mychild();
break;
}

if(close(pfdto[0])==-1)
syserr("close");
if(close(pfdfrom[1])==-1)
syserr("close");

if(signal(SIGCLD,myquitsig)==BADSIG)
syserr("signal");
if(signal(SIGINT,myquitsig)==BADSIG)
syserr("signal");
if(signal(SIGTERM,myquitsig)==BADSIG)
syserr("signal");
if(signal(SIGPIPE,myquitsig)==BADSIG)
syserr("signal");

/****************MAIN-LOOP***************************/

cptrd=linebuffer;
puts("TINTIN IS ON THE ROAD AGAIN!!!!!!! KILLKILLKILL!!!!\n");

for(;;) {

gettelnetoutput();

if(dun==0) { /*make pipes none-buffered, only done once */
flag=fcntl(0,F_GETFL ,0); /*this is weird, but it MUST be right here*/
fcntl(0,F_SETFL,flag | O_NDELAY);
flag=fcntl(pfdfrom[0],F_GETFL ,0);
fcntl(pfdfrom[0],F_SETFL,flag | O_NDELAY);
dun=1;
}

getuserinput();
}

}

/**********************************************/
/* GET OUTPUT FROM TELNET AND CUT INTO LINES */
/**********************************************/
void gettelnetoutput()
{
char *cpbuffersource;
int chargot;

if((chargot=read(pfdfrom[0],buffer,512))>0) {
write(1,buffer,chargot);

cpbuffersource=buffer;

while(cpbuffersource<buffer+chargot) {
if(*cpbuffersource=='\n') {
*cpbufferdest='\0';
cpbufferdest=linebuffer;
cpbuffersource++;
check_action();
}
else
*cpbufferdest++=*cpbuffersource++;
}
}
}

/***********************/
/* check for an action */
/***********************/
void check_action()
{
int i;
char *cp, outtext[512];

i=-1;
while(++i<actionno) {
if(actionleft[i][0]=='&' && (cp=strchr(linebuffer+1,' '))!=NULL &&
stricmp(&actionleft[i][2], cp+1)==NULL) {
*cp='\0';
substitute_alias(actionright[i], outtext, linebuffer+1 );
parse_input(outtext);
break;
}
else if(stricmp(&actionleft[i][0], linebuffer+1)==NULL) {
printf("[%s]\n",actionright[i]);
parse_input(actionright[i]);
}
}
}

/**************************************/
/* READ USER INPUT AND SEND TO PARSER */
/**************************************/
void getuserinput()
{
char inputline[512];
int inputlinelen;

inputlinelen=read(0, inputline, 80);
if(inputlinelen>=0) {
inputline[inputlinelen-1]='\0';
parse_input(inputline);
}
}

/********************************/
/* SEND A TEXT-STRING TO TELNET */
/********************************/
void sendtotelnet(char *cptr)
{
char textout[512];
int i;

strcpy(textout, cptr);
textout[i=strlen(cptr)]='\n';
if(write(pfdto[1], textout, i+1)==-1)
syserr("write");
}

/****************************/
/* SUB-ROUNTINES FOR TICKER */
/****************************/
void tickon()
{
tickswitch=1;
time0=time(NULL);
if(signal(SIGALRM,tickfunc)==BADSIG)
syserr("signal");
alarm(1);
printf("#TICKER IS NOW RUNNING AND RESET\n>");
}

void tickoff()
{
tickswitch=0;
printf("#TICKER IS NOW OFF\n>");
}

static void tickfunc()
{
if(tickswitch) {
alarm(1);
sec_to_tick=75-((time(NULL)-time0)%75);
if(sec_to_tick==10)
printf("#10 SECONDS TO TICK!!!!!!!!!!\n>");
else if(sec_to_tick==5)
printf("# 5 SECONDS TO TICK!!!!!!!!!!\n>");
}
}

/*********************************************/
/* this is where we get out when telnet dies */
/*********************************************/
static void myquitsig()
{
int flag;

flag=fcntl(0,F_GETFL ,0);
fcntl(0,F_SETFL,flag & ~O_NDELAY);
printf("\n#TINTIN AND SNOWY GOES TO SLEEP.....\n");
exit(0);
}

/*************************************************/
/* print system call error message and terminate */
/* this function was lifted... SO WHAT!?!?!??! */
/*************************************************/
void syserr(char *msg)
{
extern int errno, sys_nerr;
extern char *sys_errlist[];

fprintf(stderr,"ERROR: %s (%d",msg, errno);
if(errno>0 && errno<sys_nerr)
fprintf(stderr,": %s)\n",sys_errlist[errno]);
else
fprintf(stderr,")\n");
exit(1);
}

/************************************/
/* READ AND PARSE ALIAS/ACTION FILE */
/************************************/
void read_coms(char *filename)
{
FILE *myfile;
char inputline[100],*cptr;
int aliaslen,actionlen;

if((myfile=fopen(filename,"rt"))==NULL) {
printf("#ERROR - couldn't open file:%s\n> ",filename);
return;
}

while(fgets(inputline, 100, myfile)) {
*(strchr(inputline, '\n'))='\0';
if(strncmp(inputline, "#alias ", 7)==NULL)
parse_alias(inputline+7);
if(strncmp(inputline, "#action ", 8)==NULL)
parse_action(inputline+8);
}

fclose(myfile);
}

/********************************************************/
/* Parse input from user and write to telnet input pipe */
/********************************************************/
void parse_input(char *commandline)
{
int aliascomno;

char command[512], arg[512], outtext[512];
char *cpsource, *cpdest;

if(*commandline=='\0')
sendtotelnet(commandline);

cpsource=commandline;

while(*cpsource!='\0') {

cpsource=space_out(cpsource);
cpdest=command;

while(*cpsource!=';' && *cpsource!=' ' && *cpsource!='\0')
*cpdest++=*cpsource++;
*cpdest='\0';

cpsource=space_out(cpsource);
cpdest=arg;

while(*cpsource!=';' && *cpsource!='\0')
*cpdest++=*cpsource++;
*cpdest='\0';

aliascomno=search_alias(command);
if(aliascomno<aliasno) {
substitute_alias(aliasright[aliascomno], command, arg);
parse_input(command);
}
else {
if(*command=='#')
parse_tintin(command,arg);
else {
if(*arg!='\0') {
strcat(command, " ");
strcat(command, arg);
}
sendtotelnet(command);
}
}

if(*cpsource==';')
cpsource++;
}

}

/**********************************************/
/* Parse Tintin's special commands */
/* this is where to stuff in your own comands */
/**********************************************/
void parse_tintin(char *command, char *arg)
{
char outtext[100];
int i;

/*********REPEAT COMMAND*********/
if(isdigit(*(command+1))) {
i=atoi(command+1);
if(i>0 && i<21) {
while(i-->0)
parse_input(arg);
}
else
printf("#HEY! ONLY VALUES BETWEEN 1 AND 20 ALLOWED!\n> ");
return;
}

/**********TICKON COMMAND**********/
if(stricmp("#tickon",command)==0) {
tickon();
return;
}

/**********TICKOFF COMMAND**********/
if(stricmp("#tickoff",command)==0) {
tickoff();
return;
}

/**********TICK COMMAND**********/
if(stricmp("#tick",command)==0) {
if(tickswitch)
printf("#%d SECONDS TO TICK!\n>",sec_to_tick);
else
printf("#DUNNO TIME! THE TICKER IS NOT RUNNIN!\n>");
return;
}

/**********TICKTELL COMMAND**********/
if(stricmp("#ticktell",command)==0 && *arg!='\0') {
sprintf(outtext,"tell %s there is now %d seconds to next tick.",arg,sec_to_tick);
parse_input(outtext);
return;
}

/**********ALIAS COMMAND**********/
if(stricmp("#alias",command)==0) {
if(*arg=='\0')
show_aliases();
else
parse_alias(arg);
return;
}

/**********ACTION COMMAND**********/
if(stricmp("#action",command)==0) {
if(*arg=='\0')
show_actions();
else
parse_action(arg);
return;
}

/**********READCOMS**************/
if(stricmp("#readcoms",command)==0) {
if(*arg=='\0')
printf("#READ WHAT FILE?\n> ");
else
read_coms(arg);
return;
}

/************HELP************/
if(stricmp("#help",command)==0) {
printf("#LIST OF TINTIN-COMMANDS:\n> ");
printf("#NUMBER COMMAND :REPEATS 'COMMAND' 'NUMBER' TIMES\n> ");
printf("#ACTION [TEXT[=[TEXT]]] :LIST/DELETE/DISPLAY/DEFINE ACTIONS\n> ");
printf("#ALIAS [TEXT[=[TEXT]]] :LIST/DELETE/DISPLAY/DEFINE ALIASES\n> ");
printf("#HELP :THIS TEXT\n> ");
printf("#READCOMS FILENAME :READS A FILE WITH ACTIONS/ALIASES DEFS.\n> ");
printf("#TICKON :TURNS TICK-CLOCK/WARNINGS ON\n> ");
printf("#TICKOFF :TURNS TICK-CLOCK/WARNINGS OFF\n> ");
printf("#TICK :SHOWS #SECONDS TO NEXT TICK\n> ");
printf("#TICKTELL PLAYER :TELLS 'PLAYER' #SECONDS TO TICK\n> ");
return;
}

printf("#UNKNOWN TINTIN COMMAND!\n> ");
}

/**************************************/
/* Substitute all '&'s with cpsubtext */
/**************************************/
void substitute_alias(char *cpsource, char *cpdest, char *cpsubtext)
{
int subtextlen=strlen(cpsubtext);

while(*cpsource) {
if(*cpsource=='&') {
if(*cpsubtext=='\0') {
*cpdest++=' ';
cpsource++;
}
else {
strcpy(cpdest, cpsubtext);
cpdest+=subtextlen;
cpsource++;
}
}
else
*cpdest++=*cpsource++;
}
*cpdest='\0';
}

/*********************************************/
/* search for alias in list */
/* return alias index or aliasno if notfound */
/*********************************************/
int search_alias(char *cptr)
{
int i=-1;
while(++i<aliasno && stricmp(aliasleft[i], cptr));
return i;
}

/***********************************************/
/* search for action in list */
/* return action index or actionno if notfound */
/***********************************************/
int search_action(char *cptr)
{
int i=-1;
while(++i<actionno && stricmp(actionleft[i], cptr));
return i;
}

/**************************************/
/* move pointer to next no-space-char */
/**************************************/
char *space_out(char *cptr)
{
while(*cptr==' ')
cptr++;
return cptr;
}

/***********************************/
/* PARSE AN ALIAS. ADD/DELETE/SHOW */
/***********************************/
void parse_alias(char *cptr)
{
int i,j;
char *left,*right,*cptr2;

left=cptr=space_out(cptr);

while(*cptr!='=' && *cptr!=' ' && *cptr!='\0')
cptr++;

cptr2=strchr(cptr, '=');

*cptr='\0';

if(cptr2==NULL) {
if((i=search_alias(left))<aliasno)
printf("#ALIAS: %s=%s\n> ",aliasleft[i],aliasright[i]);
else
printf("#UNKNOWN ALIAS:%s\n> ",left);
}

else {
right=cptr=space_out(++cptr2);
if(*right!='\0') {
if((i=search_alias(left))==aliasno)
aliasno++;
strcpy(aliasleft[i], left);
strcpy(aliasright[i], right);
printf("#NEW ALIAS:%s=%s\n> ",left,right);
}

else {
if((i=search_alias(left))==aliasno)
printf("#UNKNOWN ALIAS:%s\n> ",left);
else {
j=i;
while(j<aliasno) {
strcpy(aliasleft[i],aliasleft[j]);
strcpy(aliasright[i],aliasright[j]);
j++;
}
aliasno--;
printf("#ALIAS DELETED\n> ");
}
}
}
}

/************************************/
/* PARSE AN ACTION. ADD/DELETE/SHOW */
/************************************/
void parse_action(char *cptr)
{
int i,j;
char *left,*right,*cptr2;

left=cptr=space_out(cptr);

while(*cptr!='=' && *cptr!='\0')
cptr++;

cptr2=strchr(cptr, '=');

*cptr='\0';

if(cptr2==NULL) {
if((i=search_action(left))<actionno)
printf("#ACTION: %s=%s\n> ",actionleft[i],actionright[i]);
else
printf("#UNKNOWN ACTION:%s\n> ",left);
}

else {
right=cptr=space_out(++cptr2);
if(*right!='\0') {
if((i=search_action(left))==actionno)
actionno++;
strcpy(actionleft[i], left);
strcpy(actionright[i], right);
printf("#NEW ACTION:%s=%s\n> ",left,right);
}

else {
if((i=search_action(left))==actionno)
printf("#UNKNOWN ACTION:%s\n> ",left);
else {
j=i;
while(j<actionno) {
strcpy(actionleft[i],actionleft[j]);
strcpy(actionright[i],actionright[j]);
j++;
}
actionno--;
printf("#ACTION DELETED\n> ");
}
}
}
}


/****************/
/* list aliases */
/****************/
void show_aliases()
{
int i=0;
printf("#THE FOLLOWING %d ALIASES IS DEFINED:\n> ",aliasno);

while(i<aliasno) {
printf("#ALIAS: %s=%s\n> ",aliasleft[i],aliasright[i]);
i++;
}
}

/****************/
/* list actions */
/****************/
void show_actions()
{
int i=0;
printf("#THE FOLLOWING %d ACTIONS IS DEFINED:\n> ",actionno);

while(i<actionno) {
printf("#ACTION: %s=%s\n> ",actionleft[i],actionright[i]);
i++;
}
}

0 new messages