/*
**
** Copyright (C) 1993 Swedish University Network (SUNET)
**
**
** This program is developed by UDAC, Uppsala University by commission
** of the Swedish University Network (SUNET).
**
** 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 FITTNESS 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; if not, write to the Free Software
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**
**
** Martin.Wendel@its.uu.se
** Torbjorn.Wictorin@its.uu.se
**
** ITS
** P.O. Box 887
** S-751 08 Uppsala
** Sweden
**
*/
#include "emil.h"
#include <assert.h>
/*
** Calculates the CRC of a BinHex file
**
*/
unsigned long
calc_crc(unsigned long crc,unsigned int c)
{
register int i;
register unsigned long tmk;
tmk = crc;
for (i = 0; i < 8; i++)
{
c <<= 1;
if ((tmk <<= 1) & 0x10000)
tmk = (tmk & 0xffff) ^ 0x1021;
tmk ^= (c >> 8);
c &= 0xff;
}
assert(tmk <= 65535); /* ELSE TRUNC / TW */
return((unsigned short)tmk);
}
/*
**
** Extract and check the CRC of a BinHex file.
**
*/
int
get_binhex_crc(struct data *d, unsigned long checksum)
{
int partlen;
/* CRC for the CRC */
checksum = calc_crc(checksum, (unsigned char)'\0');
checksum = calc_crc(checksum, (unsigned char)'\0');
if (d->offset + 2 > d->end)
{
#ifdef DEBUG
if (edebug)
fprintf(stderr, "* ERROR get_binhex_crc: Premature end of data in BinHexed file %lu", d->offset);
#endif
logger(LOG_WARNING, "get_binhex_crc: Premature end of data in BinHexed file");
return(NOK);
}
for (partlen = 1; partlen >= 0; partlen--, d->offset += 1)
{
if (((0xFF & *(d->contents + d->offset)) ^ (0xFF & (checksum >> (8*partlen))))
!= 0)
return(NOK);
}
return(OK);
}
/*
**
** Extract header from a BinHex file
**
*/
int
get_binhex_binary(struct message *m)
{
unsigned long checksum;
unsigned int filenamelen;
char flags[3];
struct data *d;
struct data *r = NULL;
unsigned long partlen;
unsigned long rlen;
char cdlen[5];
d = m->td;
checksum = 0;
d->offset = d->bodystart;
#ifdef DEBUG
if (edebug)
fprintf(stderr, "Extracting applefile");
#endif
if (d->contents == NULL)
{
#ifdef DEBUG
if (edebug)
fprintf(stderr, ", no input (failed)\n");
#endif
logger(LOG_WARNING, "get_binhex_binary: getting namelen: called with empty data");
return(NOK);
}
/* Extract filenamelen */
filenamelen = *(d->contents + d->offset);
checksum = calc_crc(0, (unsigned char) *(d->contents + d->offset));
d->offset += 1;
/* Extract name from a BinHex file */
m->sd->name = (char *)Yalloc(filenamelen + 1);
if (d->offset + filenamelen > d->end)
{
#ifdef DEBUG
if (edebug)
fprintf(stderr, ", no name (failed)\n");
#endif
logger(LOG_WARNING, "get_binhex_binary: getting name: premature end of data");
return(NOK);
}
assert (filenamelen > 0);
bcopy(d->contents + d->offset, m->sd->name, (unsigned) filenamelen);
for (partlen = 0; partlen < filenamelen; partlen++, d->offset += 1)
checksum = calc_crc(checksum, *(d->contents + d->offset));
#ifdef DEBUG
if (edebug)
fprintf(stderr, ", filename - %s, namelength %d", m->sd->name, filenamelen);
#endif
if (*(d->contents + d->offset) != '\0')
{
#ifdef DEBUG
if (edebug)
fprintf(stderr, ", no null byte (failed)\n");
#endif
logger(LOG_WARNING, "get_binhex_binary: Mandantory null byte unavailable in binhex header");
if (m->td != m->sd)
free_data(m->td);
m->td = m->sd;
return(NOK);
}
/* Move past NULL */
checksum = calc_crc(checksum, (unsigned char)'\0');
d->offset += 1;
/* Extract type of a BinHex file */
if ((d->offset + 4) > d->end)
{
#ifdef DEBUG
if (edebug)
fprintf(stderr, ", no type (failed)\n");
#endif
logger(LOG_WARNING, "get_binhex_binary: Type unavailable in binhex header");
if (m->td != m->sd)
free_data(m->td);
m->td = m->sd;
return(NOK);
}
m->sd->appletype = (char *)Yalloc(9);
bcopy(d->contents + d->offset, m->sd->appletype, 4);
for (partlen = 0; partlen < 4; partlen++, d->offset += 1)
checksum = calc_crc(checksum, *(d->contents + d->offset));
/* Extract auth of a BinHex file */
if ((d->offset + 4) > d->end)
{
#ifdef DEBUG
if (edebug)
fprintf(stderr, ", no auth (failed)\n");
#endif
logger(LOG_WARNING, "get_binhex_binary: Auth unavailable in binhex header");
if (m->td != m->sd)
free_data(m->td);
m->td = m->sd;
return(NOK);
}
bcopy(d->contents + d->offset, m->sd->appletype + 4, 4);
#ifdef DEBUG
if (edebug)
fprintf(stderr, ", type&creator - %s", m->sd->appletype);
fflush(stderr);
#endif
for (partlen = 0; partlen < 4; partlen++, d->offset += 1)
checksum = calc_crc(checksum, *(d->contents + d->offset));
if ((m->sd->type = confextr("APPLEFILE", m->sd->appletype, NULL)) == NULL)
if ((m->sd->type = confextr("APPLEFILE", "DEFAULT", NULL)) == NULL)
m->sd->type = NEWSTR("APPLICATION");
/* Extract flags of a BinHex file. */
if ((d->offset + 2) > d->end)
{
#ifdef DEBUG
if (edebug)
fprintf(stderr, ", no flags (failed)\n");
#endif
logger(LOG_WARNING, "get_binhex_binary: Flags unavailable in binhex header");
if (m->td != m->sd)
free_data(m->td);
m->td = m->sd;
return(NOK);
}
/* These might just as well be junked */
bzero(flags, 3);
bcopy(d->contents + d->offset, flags, 2);
for (partlen = 0; partlen < 2; partlen++, d->offset += 1)
checksum = calc_crc(checksum, *(d->contents + d->offset));
/* Extract datafork length of a BinHex file. */
if ((d->offset + 4) > d->end)
{
#ifdef DEBUG
if (edebug)
fprintf(stderr, ", no data fork length (failed)\n");
#endif
logger(LOG_WARNING, "get_binhex_binary: Data length unavailable in binhex header");
if (m->td != m->sd)
free_data(m->td);
m->td = m->sd;
return(NOK);
}
bzero(cdlen, 5);
bcopy(d->contents + d->offset, cdlen, 4);
for (partlen = 0; partlen < 4; partlen++, d->offset += 1)
checksum = calc_crc(checksum, *(d->contents + d->offset));
d->length = getblong(cdlen);
#ifdef DEBUG
if (edebug)
fprintf(stderr, ", data fork length: %lu", d->length);
#endif
/* Extract resource fork length of a BinHex file. */
/* This really not interesting until we support resource forks */
if ((d->offset + 4) > d->end)
{
#ifdef DEBUG
if (edebug)
fprintf(stderr, ", no resource fork length (failed)\n");
#endif
logger(LOG_WARNING, "get_binhex_binary: Resource length unavailable in binhex header");
if (m->td != m->sd)
free_data(m->td);
m->td = m->sd;
return(NOK);
}
bzero(cdlen, 5);
bcopy(d->contents + d->offset, cdlen, 4);
for (partlen = 0; partlen < 4; partlen++, d->offset += 1)
checksum = calc_crc(checksum, *(d->contents + d->offset));
if ((rlen = getblong(cdlen)) != 0)
m->sd->applefile = ABINHEX;
#ifdef DEBUG
if (edebug)
fprintf(stderr, ", resource fork length: %lu", rlen);
#endif
/* Check header CRC */
if (get_binhex_crc(d, checksum) != OK)
{
#ifdef DEBUG
if (edebug)
fprintf(stderr, ", header CRC error (failed)\n");
#endif
logger(LOG_WARNING, "get_binhex_binary: CRC Error in header");
if (m->td != m->sd)
free_data(m->td);
m->td = m->sd;
return(NOK);
}
/* Extract and output the datafork */
if (process)
{
d->bodystart = d->offset;
d->bodyend = d->offset + d->length;
}
if (d->offset + d->length > d->end)
{
#ifdef DEBUG
if (edebug && process)
{
fprintf(stderr, ", premature end of data in data fork (failed)\n");
fprintf(stderr, "suggested offset %lu suggested length %lu real length %lu\n",
d->offset, d->length, d->end);
}
#endif
if (process)
logger(LOG_WARNING, "get_binhex_binary: getting datafork: premature end of data");
if (m->td != m->sd)
free_data(m->td);
m->td = m->sd;
return(NOK);
}
checksum = 0;
for(partlen = 0; partlen < d->length; partlen++, d->offset += 1)
{
checksum = calc_crc(checksum, (unsigned char)*(d->contents + d->offset));
}
if (get_binhex_crc(d, checksum) != OK)
{
#ifdef DEBUG
if (edebug)
fprintf(stderr, ", data fork CRC error at offset %lu (failed)\n", d->offset);
#endif
logger(LOG_WARNING, "get_binhex_binary: CRC Error in data fork");
if (m->td != m->sd)
free_data(m->td);
m->td = m->sd;
return(NOK);
}
/* Extract and output the resource fork */
if (rlen != 0)
{
if (d->offset + rlen <= d->end)
{
if (process)
{
r = (struct data *)Yalloc(sizeof(struct data));
r->bodystart = d->offset;
r->bodyend = d->offset + rlen;
r->contents = d->contents;
r->appletype = d->appletype;
r->name = d->name;
r->type = d->type;
r->applefile = ARESOURCE;
d->applefile = AFILE;
}
}
else
{
#ifdef DEBUG
if (edebug)
fprintf(stderr, ", premature end of data in resource fork (failed) %lu\n", r->offset);
#endif
logger(LOG_WARNING, "get_binhex_binary: getting resource fork: premature end of data");
if (m->td != m->sd)
free_data(m->td);
m->td = m->sd;
return(NOK);
}
}
checksum = 0;
for(partlen = 0; partlen < rlen; partlen++, d->offset += 1)
{
checksum = calc_crc(checksum, (unsigned char)*(d->contents + d->offset));
}
if (get_binhex_crc(d, checksum) == OK)
{
#ifdef DEBUG
if (edebug)
fprintf(stderr, ", done (OK).\n");
#endif
if (r != NULL)
{
d->next = r;
r->encoding = EBINARY;
}
d->encoding = EBINARY;
return(OK);
}
else
{
#ifdef DEBUG
if (edebug)
fprintf(stderr, ", resource fork CRC error (failed)\n");
#endif
logger(LOG_WARNING, "get_binhex_binary: CRC Error in resource fork");
if (m->td != m->sd)
free_data(m->td);
m->td = m->sd;
return(NOK);
}
}
int
create_binhex_binary(struct message *m)
{
unsigned long filenamelen;
char four[5];
struct data *d, *r, *h;
unsigned long crc;
unsigned long dlen, rlen;
unsigned long partlen;
h = (struct data *) Yalloc(sizeof(struct data ));
if ((d = m->td) != NULL)
{
d->offset = d->bodystart;
}
if ((r = d->next) != NULL)
{
r->offset = r->bodystart;
}
#ifdef DEBUG
if (edebug)
fprintf(stderr, " Creating binhex binary");
#endif
if (m->sd->name == NULL)
m->sd->name = NEWSTR("noname");
filenamelen = strlen(m->sd->name);
#ifdef DEBUG
if (edebug)
fprintf(stderr, ", filename: %s", m->sd->name);
#endif
/* Add filenamelen */
append_char(h, (char) (0xff & filenamelen), pz);
/* Add filename */
append_data(h, m->sd->name, filenamelen, pz);
/* Add mandantory NULL byte */
append_char(h, '\0', pz);
#ifdef DEBUG
if (edebug)
fprintf(stderr, ", type&creator: %s\n", m->sd->appletype);
#endif
/* Add type */
append_data(h, m->sd->appletype, 4, pz);
/* Add auth */
append_data(h, m->sd->appletype + 4, 4, pz);
/* Add flags */
append_data(h, "\0\0\0", 2, pz);
/* Add data fork length */
dlen = d->bodyend - d->bodystart;
bzero(four, 5);
for (partlen = 4; partlen > 0; partlen--)
{
four[4 - partlen] = (char) 0xff & (dlen >> ((partlen - 1) * 8));
}
append_data(h, four, 4, pz);
#ifdef DEBUG
if (edebug)
fprintf(stderr, ", data length: %lu", dlen);
#endif
/* Add resource fork length */
if (r != NULL)
{
rlen = r->bodyend - r->bodystart;
}
else
{
rlen = 0; /* Resource fork is empty */
}
bzero(four, 5);
for (partlen = 4; partlen > 0; partlen--)
{
four[4 - partlen] = (char) 0xff & (rlen >> ((partlen - 1) * 8));
}
append_data(h, four, 4, pz);
#ifdef DEBUG
if (edebug)
fprintf(stderr, ", resource length: %lu\n", rlen);
#endif
/* Generate header CRC */
crc = 0;
for (partlen = 0; partlen < h->bodyend; partlen++)
{
crc = calc_crc(crc, *(h->contents + partlen));
}
crc = calc_crc(crc, '\0');
crc = calc_crc(crc, '\0');
bzero(four, 5);
for (partlen = 2; partlen > 0; partlen--)
{
four[2 - partlen] = (char) 0xff & (crc >> ((partlen - 1) * 8));
}
append_data(h, four, 2, pz);
dlen = d->bodyend - d->bodystart;
partlen = h->bodyend;
/* Append data fork */
append_data(h, d->contents + d->bodystart, dlen, pz);
#ifdef DEBUG
if (edebug)
fprintf(stderr, "Append data fork: old end %lu, new end %lu, length %lu\n", partlen, h->bodyend, dlen);
#endif
/* Append data CRC */
crc = 0;
for (; partlen < h->bodyend; partlen++)
{
crc = calc_crc(crc, *(h->contents + partlen));
}
crc = calc_crc(crc, (unsigned char)'\0');
crc = calc_crc(crc, (unsigned char)'\0');
bzero(four, 5);
for (partlen = 2; partlen > 0; partlen--)
{
four[2 - partlen] = (char) 0xff & (crc >> ((partlen - 1) * 8));
}
append_data(h, four, 2, pz);
/* Append resource fork */
crc = 0;
partlen = h->bodyend;
if (r != NULL)
{
rlen = r->bodyend - r->bodystart;
append_data(h, r->contents + r->bodystart, rlen, pz);
#ifdef DEBUG
if (edebug)
fprintf(stderr, "Append resource fork: old end %lu, new end %lu, length %lu\n", partlen, h->bodyend, rlen);
#endif
/* Append resource CRC */
for (partlen = h->bodyend - rlen; partlen < h->bodyend; partlen++)
{
crc = calc_crc(crc, *(h->contents + partlen));
}
}
crc = calc_crc(crc, '\0');
crc = calc_crc(crc, '\0');
bzero(four, 5);
for (partlen = 2; partlen > 0; partlen--)
{
four[2 - partlen] = (char) 0xff & (crc >> ((partlen - 1) * 8));
}
append_data(h, four, 2, pz);
safe_mchange(m, h);
return(OK);
}
syntax highlighted by Code2HTML, v. 0.9.1