/*
* IMC2 - an inter-mud communications protocol
*
* imc-version.c: packet generation/interpretation for various protocol
* versions
*
* Copyright (C) 1996,1997 Oliver Jowett <oliver@jowett.manawatu.planet.co.nz>
*
* 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 (see the file COPYING); if not, write to the
* Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#define IMC_INTERNALS
#include "imc.h"
static const char *generate2(const imc_packet *);
static imc_packet *interpret2(const char *);
_imc_vinfo imc_vinfo[] =
{
{ 0, NULL, NULL },
{ 1, NULL, NULL },
{ 2, generate2, interpret2 }
};
/* escape2: escape " -> \", \ -> \\, CR -> \r, LF -> \n */
static const char *escape2(const char *data)
{
char *buf=imc_getsbuf(IMC_DATA_LENGTH);
char *p;
for (p=buf; *data && (p-buf < IMC_DATA_LENGTH-1); data++, p++)
{
if (*data == '\n')
{
*p++='\\';
*p='n';
}
else if (*data == '\r')
{
*p++='\\';
*p='r';
}
else if (*data == '\\')
{
*p++='\\';
*p='\\';
}
else if (*data == '"')
{
*p++='\\';
*p='"';
}
else
*p=*data;
}
*p=0;
imc_shrinksbuf(buf);
return buf;
}
/* printkeys: print key-value pairs, escaping values */
static const char *printkeys(const imc_data * data)
{
char *buf=imc_getsbuf(IMC_DATA_LENGTH);
char temp[IMC_DATA_LENGTH];
int len=0;
int i;
buf[0]=0;
for (i=0; i<IMC_MAX_KEYS; i++)
{
if (!data->key[i])
continue;
imc_sncpy(buf+len, data->key[i], IMC_DATA_LENGTH-len-1);
strcat(buf, "=");
len = strlen(buf);
if (!strchr(data->value[i], ' '))
imc_sncpy(temp, escape2(data->value[i]), IMC_DATA_LENGTH-1);
else
{
temp[0]='"';
imc_sncpy(temp+1, escape2(data->value[i]), IMC_DATA_LENGTH-3);
strcat(temp, "\"");
}
strcat(temp, " ");
imc_sncpy(buf+len, temp, IMC_DATA_LENGTH-len);
len = strlen(buf);
}
imc_shrinksbuf(buf);
return buf;
}
/* parsekeys: extract keys from string */
static void parsekeys(const char *string, imc_data * data)
{
const char *p1;
char *p2;
char k[IMC_DATA_LENGTH], v[IMC_DATA_LENGTH];
int quote;
p1 = string;
while (*p1)
{
while (*p1 && isspace(*p1))
p1++;
p2 = k;
while (*p1 && *p1 != '=' && p2-k < IMC_DATA_LENGTH-1)
*p2++=*p1++;
*p2=0;
if (!k[0] || !*p1) /* no more keys? */
break;
p1++; /* skip the '=' */
if (*p1 == '"')
{
p1++;
quote = 1;
}
else
quote = 0;
p2=v;
while (*p1 && (!quote || *p1 != '"') && (quote || *p1 != ' ') &&
p2-v < IMC_DATA_LENGTH+1)
{
if (*p1 == '\\')
{
switch (*(++p1))
{
case '\\':
*p2++='\\';
break;
case 'n':
*p2++='\n';
break;
case 'r':
*p2++='\r';
break;
case '"':
*p2++='"';
break;
default:
*p2++=*p1;
break;
}
if (*p1)
p1++;
}
else
*p2++=*p1++;
}
*p2=0;
if (!v[0])
continue;
imc_addkey(data, k, v);
if (quote && *p1)
p1++;
}
}
static const char *generate2(const imc_packet * p)
{
char *temp;
char newpath[IMC_PATH_LENGTH];
if (!p->type[0] || !p->i.from[0] || !p->i.to[0])
{
imc_logerror("BUG: generate2: bad packet!");
return NULL; /* catch bad packets here */
}
if (!p->i.path[0])
strcpy(newpath, imc_name);
else
sprintf(newpath, "%s!%s", p->i.path, imc_name);
temp=imc_getsbuf(IMC_PACKET_LENGTH);
sprintf(temp, "%s %lu %s %s %s %s",
p->i.from, p->i.sequence, newpath, p->type, p->i.to,
printkeys(&p->data));
imc_shrinksbuf(temp);
return temp;
}
static imc_packet *interpret2(const char *argument)
{
char seq[20];
static imc_packet out;
imc_initdata(&out.data);
argument=imc_getarg(argument, out.i.from, IMC_NAME_LENGTH);
argument=imc_getarg(argument, seq, 20);
argument=imc_getarg(argument, out.i.path, IMC_PATH_LENGTH);
argument=imc_getarg(argument, out.type, IMC_TYPE_LENGTH);
argument=imc_getarg(argument, out.i.to, IMC_NAME_LENGTH);
if (!out.i.from[0] || !seq[0] || !out.i.path[0] || !out.type[0] || !out.i.to[0])
{
imc_logerror("interpret2: bad packet received, discarding");
return NULL;
}
parsekeys(argument, &out.data);
out.i.sequence=strtoul(seq, NULL, 10);
return &out;
}