File indexing completed on 2024-12-01 06:51:48

0001 /**
0002  * KMuddy scripting - variable support
0003  *
0004  * #include this file in a C/C++ script, if you want to use variables
0005  * in that script.
0006  *
0007  * */
0008 
0009 /* PUBLIC INTERFACE: */
0010 
0011 /** call this at the beginning of your script */
0012 void initVariableSocket ();
0013 
0014 /** call this at the end of your script */
0015 void closeVariableSocket ();
0016 
0017 /** call this to set your script up to listen on an IP port */
0018 void initIPPort(const int ip_port);
0019 
0020 /** wait for and retrieve event notification from IP port */
0021 void getEvent (char *buffer, int buflen);
0022 
0023 /** reads variable value and store it in the buffer (of size buflen+1) */
0024 void getVariable (const char *name, char *buffer, int buflen);
0025 
0026 /** sets a variable value */
0027 char setVariable (const char *name, const char *value);
0028 
0029 /** unsets a variable */
0030 char unsetVariable (const char *name);
0031 
0032 /** increases a variable value */
0033 char incVariable (const char *name, int delta);
0034 
0035 /** decreases a variable value */
0036 char decVariable (const char *name, int delta);
0037 
0038 /** provide a resource */
0039 char provideResource (const char *name);
0040 
0041 /** request a resource */
0042 char requestResource (const char *name);
0043 
0044 /** request variable lock */
0045 char lockVariable (const char *name);
0046 
0047 /** unlock a variable */
0048 void unlockVariable (const char *name);
0049 
0050 /** sends a command to the MUD */
0051 char sendCommand (const char *command);
0052 
0053 
0054 
0055 
0056 /* INTERNAL VARIABLES AND FUNCTIONS -- DO NOT USE IN THE SCRIPT */
0057 #define MAX_PENDING_CONNECTIONS 5
0058 char internalBuffer[51];
0059 int variableSocket = -1;
0060 int serverSocket   = -1;
0061 int clientSocket   = -1;
0062 char simpleCommand (const char *command, const char *name);
0063 
0064 void sendAndReceive (const char *sendthis, char *buffer, int buflen);
0065 
0066 /* IMPLEMENTATION */
0067 
0068 #include <errno.h>
0069 
0070 #include <stdio.h>
0071 #include <stdlib.h>
0072 #include <string.h>
0073 #include <unistd.h>
0074 #include <sys/socket.h>
0075 #include <sys/types.h>
0076 #include <sys/un.h>
0077 #include <netinet/in.h>
0078 #include <arpa/inet.h>
0079 #include <kvbox.h>
0080 
0081 
0082 void initVariableSocket ()
0083 {
0084    struct sockaddr_un sa;
0085    char *path;
0086    path = getenv ("KMUDDY_SOCKET");
0087    if (!path)
0088    {
0089       puts ("Variable KMUDDY_SOCKET is not set - variable support won't work!\n");
0090       fflush (stdout);
0091       return; /* bah! */
0092    }
0093    variableSocket = socket (PF_UNIX, SOCK_STREAM, 0);
0094    sa.sun_family = AF_UNIX;
0095    strcpy (sa.sun_path, path);
0096    if (connect (variableSocket, (struct sockaddr *) &sa, sizeof (sa)) == -1)
0097    {
0098       close (variableSocket);
0099       variableSocket = -1;  /* :( */
0100       puts ("Could not connect to KMuddy!\n");
0101       printf ("Error = %s\n", strerror (errno));
0102       fflush (stdout);
0103    }
0104    /* okay, we should be connected now... */
0105 }
0106 
0107 void closeVariableSocket ()
0108 {
0109   if (variableSocket != -1)
0110      close (variableSocket);
0111 
0112   if (serverSocket != -1)
0113      close (serverSocket);
0114 
0115   if (clientSocket != -1)
0116      close(clientSocket);
0117 
0118 }
0119 
0120 
0121 /** call this to set your script up to listen on an IP port */
0122 void initIPPort(const int ip_port)
0123 {
0124    struct sockaddr_in server_address;
0125    int                val = 1;
0126    int                result;
0127 
0128    serverSocket = socket(AF_INET,
0129                          SOCK_STREAM,
0130                          0);
0131 
0132    if (serverSocket < 0)
0133    {
0134       puts ("Unable to create a socket - server support won't work!\n");
0135       fflush (stdout);
0136       return; /* bah! */
0137    } /* endif unable to obtain a socket */
0138 
0139    result = setsockopt(serverSocket,
0140                        SOL_SOCKET,
0141                        SO_REUSEADDR,
0142                        (char *)&val,
0143                        sizeof(val));
0144 
0145    if (result != 0)
0146    {
0147       close(serverSocket);
0148       puts ("Unable to modify socket options - server support won't work!\n");
0149       fflush (stdout);
0150       return; /* bah! */
0151    } /* endif unable to modify socket options */
0152 
0153    server_address.sin_family      = AF_INET;
0154    server_address.sin_addr.s_addr = htonl(INADDR_ANY);
0155    server_address.sin_port        = htons(ip_port);
0156 
0157    result = bind(serverSocket,
0158                  (struct sockaddr *)&server_address,
0159                  sizeof(server_address));
0160 
0161    if (result != 0)
0162    {
0163       close(serverSocket);
0164       puts ("Unable to bind socket to specified IP port - server support won't work!\n");
0165       fflush (stdout);
0166       return; /* bah! */
0167    } /* endif unable to modify socket options */
0168 
0169    result = listen(serverSocket,
0170                    MAX_PENDING_CONNECTIONS);
0171 
0172    if (result != 0)
0173    {
0174       close(serverSocket);
0175       puts ("Unable to listen on specified IP port - server support won't work!\n");
0176       fflush (stdout);
0177       return; /* bah! */
0178    } /* endif unable to modify socket options */
0179 
0180 } /* initIPPort */
0181 
0182 
0183 /** wait for and retrieve event notification from IP port */
0184 void getEvent (char *buffer, int buflen)
0185 {
0186    struct sockaddr_in client_address;
0187 
0188    int   client_name_size;
0189    char *dest;
0190    int   finished = 0;
0191    int   remaining;
0192    int   received;
0193    int   total;
0194 
0195    /* Buffer to store incoming TCP/IP data */
0196    static char recv_buffer[1024];
0197    const int   recv_buffer_maxsize = 1024;
0198    static int  recv_amount = 0;  /* Amount actually received from the network */
0199    static int  recv_offset = 0;  /* Amount processed so far */
0200    static int  need_skip   = 0;  /* Set if we need to ignore everything until next \n */
0201 
0202    int buffer_offset = 0;
0203 
0204    buffer[0] = '\0';
0205 
0206    if (serverSocket == -1)
0207    {
0208       return;
0209    } /* endif not listening on IP port */
0210 
0211    if (clientSocket == -1)
0212    {
0213       /* Debug message */
0214 /*
0215       puts ("No previous connection from KMuddy - waiting for connection\n");
0216       fflush (stdout);
0217 */
0218 
0219       client_name_size = sizeof(client_address);
0220 
0221       clientSocket = accept(serverSocket,
0222                             (struct sockaddr *)&client_address,
0223                             (socklen_t *)&client_name_size);
0224 
0225    } // endif no previous dialogue with server
0226 
0227    if (clientSocket < 0)
0228    {
0229       return;
0230    } /* endif accept failed */
0231 
0232 
0233    while (!finished)
0234    {
0235       if (recv_offset >= recv_amount)
0236       {
0237          recv_offset = 0;
0238 
0239          recv_amount = recv(clientSocket,
0240                             recv_buffer,
0241                             recv_buffer_maxsize,
0242                             0);
0243 
0244       } /* endif need to receive more data from the network */
0245 
0246       if (need_skip)
0247       {
0248          while ((recv_offset               < recv_amount)&&
0249                 (recv_buffer[recv_offset] != '\n')         )
0250          {
0251             recv_offset++;
0252          } /* endwhile more characters to skip */
0253 
0254          if (recv_offset < recv_amount)
0255          {
0256             recv_offset++;
0257             need_skip = 0;
0258          } /* endif found \n */
0259 
0260       } /* endif need to ignore everything until next \n */
0261 
0262       while ((recv_offset               < recv_amount)&&
0263              (buffer_offset             < buflen-1)   &&
0264              (recv_buffer[recv_offset] != '\n')         )
0265       {
0266          buffer[buffer_offset++] = recv_buffer[recv_offset++];
0267 
0268       } /* endwhile not found complete message yet */
0269 
0270       if (buffer_offset == buflen-1)
0271       {
0272          /* Truncate message */
0273          buffer[buflen-1] = '\0';
0274          finished         = 1;
0275          need_skip        = 1; /* need to ignore everything until next \n */
0276       } /* endif reached limits of message buffer */
0277       else if (recv_offset < recv_amount)
0278       {
0279          /* Found \n at recv_offset */
0280          buffer[buffer_offset] = '\0';
0281          finished = 1;
0282          recv_offset++;
0283       } /* endif received full message */
0284 
0285    } /* endwhile more work to do to receive complete message */
0286 
0287 } /* getEvent */
0288 
0289 
0290 
0291 void getVariable (const char *name, char *buffer, int buflen)
0292 {
0293   int n;
0294    /* some initial tests */
0295    if (!name) return;
0296    if (!buffer) return;
0297    if (buflen <= 0) return;
0298    //alocate memory for request-string
0299    n = strlen (name);
0300    char *request = (char *) malloc (6 + n);
0301    //build a request
0302    strcpy (request, "get ");
0303    strcat (request, name);
0304    strcat (request, "\n");
0305    /* send it and receive the result */
0306    sendAndReceive (request, buffer, buflen);
0307    /* free up memory used by the request-string */
0308    free (request);
0309 }
0310 
0311 char setVariable (const char *name, const char *value)
0312 {
0313   int n1, n2;
0314   /* some initial tests */
0315   if (!name) return 0;
0316    if (!value) return 0;
0317    /* allocate memory for request-string */
0318    n1 = strlen (name);
0319    n2 = strlen (value);
0320    char *request = (char *) malloc (7 + n1 + n2);
0321    /* build a request */
0322    strcpy (request, "set ");
0323    strcat (request, name);
0324    strcat (request, " ");
0325    strcat (request, value);
0326    strcat (request, "\n");
0327    /* send it and receive the result */
0328    sendAndReceive (request, internalBuffer, 51);
0329    /* free up memory used by the request-string */
0330    free (request);
0331 
0332    if (strncmp (internalBuffer, "OK", 2) == 0)
0333       return 1;  /* success */
0334    return 0;  /* failure */
0335 }
0336 
0337 char unsetVariable (const char *name)
0338 {
0339   return simpleCommand ("unset", name);
0340 }
0341 
0342 char incVariable (const char *name, int delta)
0343 {
0344   int n1, n2;
0345   /* some initial tests */
0346   if (!name) return 0;
0347    if (delta <= 0) return 0;
0348    //alocate memory for request-string
0349    n1 = strlen (name);
0350    n2 = 10;
0351    char *request = (char *) malloc (7 + n1 + n2);
0352    char *value = (char *) malloc (10);
0353    sprintf (value, "%d", delta);
0354    //build a request
0355    strcpy (request, "inc ");
0356    strcat (request, name);
0357    strcat (request, " ");
0358    strcat (request, value);
0359    strcat (request, "\n");
0360    /* send it and receive the result */
0361    sendAndReceive (request, internalBuffer, 51);
0362    /* free up memory used by the request-string */
0363    free (request);
0364 
0365    if (strncmp (internalBuffer, "OK", 2) == 0)
0366       return 1;  /* success */
0367    return 0;  /* failure */
0368 }
0369 
0370 char decVariable (const char *name, int delta)
0371 {
0372   int n1, n2;
0373   /* some initial tests */
0374   if (!name) return 0;
0375    if (delta <= 0) return 0;
0376    /* allocate memory for request-string */
0377    n1 = strlen (name);
0378    n2 = 10;
0379    char *request = (char *) malloc (7 + n1 + n2);
0380    char *value = (char *) malloc (10);
0381    sprintf (value, "%d", delta);
0382    /* build a request */
0383    strcpy (request, "dec ");
0384    strcat (request, name);
0385    strcat (request, " ");
0386    strcat (request, value);
0387    strcat (request, "\n");
0388    /* send it and receive the result */
0389    sendAndReceive (request, internalBuffer, 51);
0390    /* free up memory used by the request-string */
0391    free (request);
0392 
0393    if (strncmp (internalBuffer, "OK", 2) == 0)
0394       return 1;  /* success */
0395    return 0;  /* failure */
0396 }
0397 
0398 char provideResource (const char *name)
0399 {
0400   return simpleCommand ("provide", name);
0401 }
0402 
0403 char requestResource (const char *name)
0404 {
0405   return simpleCommand ("request", name);
0406 }
0407 
0408 char lockVariable (const char *name)
0409 {
0410   return simpleCommand ("lock", name);
0411 }
0412 
0413 void unlockVariable (const char *name)
0414 {
0415   simpleCommand ("unlock", name);
0416 }
0417 
0418 char simpleCommand (const char *command, const char *name)
0419 {
0420   int n,k;
0421   /* some initial tests */
0422   if (!name) return 0;
0423    /* allocate memory for request-string */
0424    n = strlen (name);
0425    k = strlen (command);
0426    char *request = (char *) malloc (3 + k + n);
0427    /* build a request */
0428    strcpy (request, command);
0429    strcat (request, " ");
0430    strcat (request, name);
0431    strcat (request, "\n");
0432    /* send it and receive the result */
0433    sendAndReceive (request, internalBuffer, 51);
0434    /* free up memory used by the request-string */
0435    free (request);
0436 
0437    if (strncmp (internalBuffer, "OK", 2) == 0)
0438       return 1;  /* success */
0439    return 0;  /* failure */
0440 }
0441 
0442 void sendAndReceive (const char *sendthis, char *buffer, int buflen)
0443 {
0444   int n;
0445    int tobewritten, remaining;
0446    const char *sendme;
0447    char myBuf[101];
0448    char gotNewLine = 0;
0449    buffer[0] = '\0';
0450 
0451    if (variableSocket == -1)
0452       return;
0453   tobewritten = strlen (sendthis);
0454    if (tobewritten == 0)
0455       return;
0456    /* pointer to data that hasn't been written yet */
0457    sendme = sendthis;
0458    /* write it all */
0459    while (tobewritten > 0)
0460    {
0461       n = write (variableSocket, sendme, strlen (sendme));
0462       if (n == -1)
0463          /* TODO: some error reporting */
0464          return;
0465       /* shift the pointer */
0466       tobewritten -= n; // Alex change - moved from above
0467       sendme += n;
0468    }
0469 
0470    /* read reply from KMuddy */
0471    remaining = buflen;  /* buffer needs to have one extra byte for \0 */
0472 
0473    while (!gotNewLine)
0474    {
0475       n = read (variableSocket, myBuf, 100);
0476 
0477       if (n == -1) /* bah! */
0478          return;
0479       myBuf[n] = '\0';
0480       if (remaining)
0481       {
0482          strncat (buffer, myBuf, remaining);
0483          remaining -= n;
0484          if (remaining < 0)
0485             remaining = 0;
0486          n = strlen (buffer);
0487          if (n)
0488             if (buffer[n - 1] == '\n')
0489             {
0490                gotNewLine = 1;
0491                buffer[n - 1] = '\0';  /* don't return that newline */
0492             }
0493       }
0494    }
0495 }
0496 
0497 
0498 
0499 /* ALEX CHANGE */
0500 char sendCommand (const char *command)
0501 {
0502   int n1;
0503    /* some initial tests */
0504   if (!command) return 0;
0505    /* allocate memory for request-string */
0506    n1 = strlen (command);
0507    char *request = (char *) malloc (7 + n1);
0508    /* build a request */
0509    strcpy (request, "send ");
0510    strcat (request, command);
0511    strcat (request, "\n");
0512    /* send it and receive the result */
0513    sendAndReceive (request, internalBuffer, 51);
0514    /* free up memory used by the request-string */
0515    free (request);
0516 
0517    if (strncmp (internalBuffer, "OK", 2) == 0)
0518       return 1;  /* success */
0519    return 0;  /* failure */
0520 }
0521 
0522 /* END ALEX CHANGE */