#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef SYSTEM_WINDLL
#include <windows.h>
#endif
#ifdef SYSTEM_OS2
#include <os2.h>
#endif
#include <stdio.h>
#include <ctype.h>
#ifdef STDC_HEADERS
#include <stdlib.h>
#include <string.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#include <crc32.h>
#include <uudeview.h>
#include <uuint.h>
#include <fptools.h>
#include <uustring.h>
char * uunconc_id = "$Id: uunconc.c,v 1.1 2004/05/14 15:23:05 dasenbro Exp $";
#ifndef SEEK_SET
#ifdef L_BEGIN
#define SEEK_SET L_BEGIN
#else
#define SEEK_SET 0
#endif
#endif
#define BEGIN (1)
#define DATA (2)
#define END (3)
#define DONE (4)
char *uunconc_UUxlat;
char *uunconc_UUxlen;
char *uunconc_B64xlat;
char *uunconc_XXxlat;
char *uunconc_BHxlat;
char *uunconc_save;
static int * UUxlen;
static int * UUxlat;
static int * B64xlat;
static int * XXxlat;
static int * BHxlat;
static char *save[3];
char *uuncdl_fulline;
char *uuncdp_oline;
static int uulboundary;
#define ACAST(s) ((int)(uchar)(s))
void
UUInitConc (void)
{
int i, j;
UUxlen = (int *) uunconc_UUxlen;
UUxlat = (int *) uunconc_UUxlat;
B64xlat = (int *) uunconc_B64xlat;
XXxlat = (int *) uunconc_XXxlat;
BHxlat = (int *) uunconc_BHxlat;
save[0] = uunconc_save;
save[1] = uunconc_save + 1200;
save[2] = uunconc_save + 2400;
for(i = 0; i < 256; i++)
UUxlat[i] = B64xlat[i] = XXxlat[i] = BHxlat[i] = -1;
for (i = ' ', j = 0; i < ' ' + 64; i++, j++)
UUxlat[i] = j;
for (i = '`', j = 0; i < '`' + 32; i++, j++)
UUxlat[i] = j;
UUxlat['`'] = UUxlat[' '];
UUxlat['~'] = UUxlat['^'];
UUxlen[0] = 1;
for(i = 1, j = 5; i <= 61; i += 3, j += 4)
UUxlen[i] = UUxlen[i+1] = UUxlen[i+2] = j;
for (i=0; i<64; i++) {
B64xlat[ACAST(B64EncodeTable[i])] = i;
XXxlat [ACAST(XXEncodeTable [i])] = i;
BHxlat [ACAST(BHEncodeTable [i])] = i;
}
}
int
UUBrokenByNetscape (char *string)
{
char *ptr;
int len;
if (string==NULL || (len=strlen(string))<3)
return 0;
if ((ptr = _FP_stristr (string, "<a href=")) != NULL) {
if (_FP_stristr (string, "</a>") > ptr)
return 2;
}
ptr = string + len;
while (len && (*(ptr-1)=='\015' || *(ptr-1)=='\012')) {
ptr--; len--;
}
if (len<3) return 0;
if (*--ptr == ' ') ptr--;
ptr--;
if (_FP_strnicmp (ptr, "<a", 2) == 0)
return 1;
return 0;
}
int
UUNetscapeCollapse (char *string)
{
char *p1=string, *p2=string;
int res = 0;
if (string==NULL)
return 0;
while (*p1) {
if (*p1 == '&') {
if (_FP_strnicmp (p1, "&", 5) == 0) { p1+=5; *p2++='&'; res=1; }
else if (_FP_strnicmp (p1, "<", 4) == 0) { p1+=4; *p2++='<'; res=1; }
else if (_FP_strnicmp (p1, ">", 4) == 0) { p1+=4; *p2++='>'; res=1; }
else *p2++ = *p1++;
res = 1;
}
else *p2++ = *p1++;
}
*p2 = '\0';
p1 = p2 = string;
while (*p1) {
if (*p1 == '<') {
if ((_FP_strnicmp (p1, "<ahref=", 7) == 0 ||
_FP_strnicmp (p1, "<a href=",8) == 0) &&
(_FP_strstr (p1, "</a>") != 0 || _FP_strstr (p1, "</A>") != 0)) {
while (*p1 && *p1!='>') p1++;
if (*p1=='\0' || *(p1+1)!='<') return 0;
p1++;
while (*p1 && (*p1!='<' || _FP_strnicmp(p1,"</a>",4)!=0)) {
*p2++ = *p1++;
}
if (_FP_strnicmp(p1,"</a>",4) != 0)
return 0;
p1+=4;
res=1;
}
else
*p2++ = *p1++;
}
else
*p2++ = *p1++;
}
*p2 = '\0';
return res;
}
int
UUValidData (char *ptr, int encoding, int *bhflag)
{
int i=0, j, len=0, suspicious=0, flag=0;
char *s = ptr;
if ((s == NULL) || (*s == '\0')) {
return 0;
}
while (*s && *s!='\012' && *s!='\015') {
s++;
len++;
i++;
}
if (i == 0)
return 0;
switch (encoding) {
case UU_ENCODED:
goto _t_UU;
case XX_ENCODED:
goto _t_XX;
case B64ENCODED:
goto _t_B64;
case BH_ENCODED:
goto _t_Binhex;
case YENC_ENCODED:
return YENC_ENCODED;
}
_t_Binhex:
len = i; s = ptr;
if (*bhflag == 0 && *s != ':') {
if (encoding==BH_ENCODED) return 0;
goto _t_B64;
}
else if (*bhflag == 0 ) {
s++; len--;
}
while (len && BHxlat[ACAST(*s)] != -1) {
len--; s++;
}
flag = (*s == ':') ? 0 : 1;
if (*s == ':' && len>0) {
s++; len--;
}
if (((i>=60 && len<=10) || encoding) && *s==' ') {
while (len && *s==' ') {
s++; len--;
}
}
if (len != 0 || (flag && i < 40)) {
if (encoding==BH_ENCODED) return 0;
goto _t_B64;
}
*bhflag = flag;
return BH_ENCODED;
_t_B64:
len = i; s = ptr;
while (len--) {
if (*s < 0 || (B64xlat[ACAST(*s)] == -1 && *s != '=')) {
if (((i>=60 && len<=10) || encoding) && *s++==' ') {
while (*s==' ' && len) s++;
if (len==0) return B64ENCODED;
}
if (encoding==B64ENCODED) return 0;
goto _t_UU;
}
else if (*s == '=') {
s++;
if (*s=='=' && len>=1) {
len--; s++;
}
if (encoding && len && *s==' ') {
while (len && *s==' ') {
s++; len--;
}
}
if (len != 0) {
if (encoding==B64ENCODED) return 0;
goto _t_UU;
}
return B64ENCODED;
}
s++;
}
return B64ENCODED;
_t_UU:
len = i; s = ptr;
if (UUxlat[ACAST(*s)] == -1) {
if (encoding==UU_ENCODED) return 0;
goto _t_XX;
}
j = UUxlen[UUxlat[ACAST(*s)]];
if (len-1 == j)
len--;
if (len != j) {
switch (UUxlat[ACAST(*s)]%3) {
case 1:
if (j-2 == len) j-=2;
break;
case 2:
if (j-1 == len) j-=1;
break;
}
}
if (len != j &&
((ptr[0] == '-' && ptr[1] == '-' && strstr(ptr,"part")!=NULL) ||
!(*ptr != 'M' && *ptr != 'h' &&
len > j && len <= UUxlen[UUxlat['M']]))) {
if (encoding==UU_ENCODED) return 0;
goto _t_XX;
}
if (len != j || islower (*ptr)) {
if (encoding != UU_ENCODED)
if (strchr (ptr, ' ') != NULL)
goto _t_XX;
len = j;
}
while (len--) {
if (*s < 0 || UUxlat[ACAST(*s++)] < 0) {
if (encoding==UU_ENCODED) return 0;
goto _t_XX;
}
if (*s == ' ' && suspicious) {
if (encoding==UU_ENCODED) return 0;
goto _t_XX;
}
}
return UU_ENCODED;
_t_XX:
len = i; s = ptr;
if (XXxlat[ACAST(*s)] == -1)
return 0;
j = UUxlen[XXxlat[ACAST(*s)]];
if (len-1 == j)
len--;
if (len != j)
switch (UUxlat[ACAST(*s)]%3) {
case 1:
if (j-2 == len) j-=2;
break;
case 2:
if (j-1 == len) j-=1;
break;
}
if (len != j && !(*ptr != 'h' && len > j && len <= UUxlen[UUxlat['h']]))
return 0;
while(len--) {
if(*s < 0 || XXxlat[ACAST(*s++)] < 0) {
return 0;
}
}
return XX_ENCODED;
}
int
UURepairData (FILE *datei, char *line, int encoding, int *bhflag)
{
int nflag, vflag=0, safety=42;
char *ptr;
nflag = UUBrokenByNetscape (line);
while (vflag == 0 && nflag && safety--) {
if (nflag == 1) {
if (strlen (line) > 250)
break;
ptr = line + strlen (line);
while (ptr>line && (*(ptr-1)=='\015' || *(ptr-1)=='\012'))
ptr--;
if (_FP_fgets (ptr, 299-(ptr-line), datei) == NULL)
break;
}
else {
}
if (UUNetscapeCollapse (line)) {
if ((vflag = UUValidData (line, encoding, bhflag)) == 0)
nflag = UUBrokenByNetscape (line);
}
else
nflag = 0;
}
if (vflag == 0) {
if (UUNetscapeCollapse (line))
vflag = UUValidData (line, encoding, bhflag);
}
if (vflag == 0) {
ptr = line + strlen(line);
while (ptr>line && (*(ptr-1)=='\012' || *(ptr-1)=='\015')) {
ptr--;
}
*ptr++ = ' ';
*ptr-- = '\0';
if ((vflag = UUValidData (line, encoding, bhflag)) != UU_ENCODED) {
*ptr = '\0';
vflag = 0;
}
}
return vflag;
}
size_t
UUDecodeLine (char *s, char *d, int method)
{
int i, j, c, cc, count=0, z1, z2, z3, z4;
static int leftover=0;
int *table;
if (s == NULL || d == NULL) {
leftover = 0;
return 0;
}
z1 = z2 = z3 = z4 = 0;
if (method == UU_ENCODED || method == XX_ENCODED) {
if (method == UU_ENCODED)
table = UUxlat;
else
table = XXxlat;
i = table [ACAST(*s++)];
j = UUxlen[i] - 1;
while(j > 0) {
c = table[ACAST(*s++)] << 2;
cc = table[ACAST(*s++)];
c |= (cc >> 4);
if(i-- > 0)
d[count++] = c;
cc <<= 4;
c = table[ACAST(*s++)];
cc |= (c >> 2);
if(i-- > 0)
d[count++] = cc;
c <<= 6;
c |= table[ACAST(*s++)];
if(i-- > 0)
d[count++] = c;
j -= 4;
}
}
else if (method == B64ENCODED) {
if (leftover) {
strcpy (uuncdl_fulline + leftover, s);
leftover = 0;
s = uuncdl_fulline;
}
while ((z1 = B64xlat[ACAST(*s)]) != -1) {
if ((z2 = B64xlat[ACAST(*(s+1))]) == -1) break;
if ((z3 = B64xlat[ACAST(*(s+2))]) == -1) break;
if ((z4 = B64xlat[ACAST(*(s+3))]) == -1) break;
d[count++] = (z1 << 2) | (z2 >> 4);
d[count++] = (z2 << 4) | (z3 >> 2);
d[count++] = (z3 << 6) | (z4);
s += 4;
}
if (z1 != -1 && z2 != -1 && *(s+2) == '=') {
d[count++] = (z1 << 2) | (z2 >> 4);
s+=2;
}
else if (z1 != -1 && z2 != -1 && z3 != -1 && *(s+3) == '=') {
d[count++] = (z1 << 2) | (z2 >> 4);
d[count++] = (z2 << 4) | (z3 >> 2);
s+=3;
}
while (B64xlat[ACAST(*s)] != -1)
uuncdl_fulline[leftover++] = *s++;
}
else if (method == BH_ENCODED) {
if (leftover) {
strcpy (uuncdl_fulline + leftover, s);
leftover = 0;
s = uuncdl_fulline;
}
else if (*s == ':')
s++;
while ((z1 = BHxlat[ACAST(*s)]) != -1) {
if ((z2 = BHxlat[ACAST(*(s+1))]) == -1) break;
if ((z3 = BHxlat[ACAST(*(s+2))]) == -1) break;
if ((z4 = BHxlat[ACAST(*(s+3))]) == -1) break;
d[count++] = (z1 << 2) | (z2 >> 4);
d[count++] = (z2 << 4) | (z3 >> 2);
d[count++] = (z3 << 6) | (z4);
s += 4;
}
if (z1 != -1 && z2 != -1 && *(s+2) == ':') {
d[count++] = (z1 << 2) | (z2 >> 4);
s+=2;
}
else if (z1 != -1 && z2 != -1 && z3 != -1 && *(s+3) == ':') {
d[count++] = (z1 << 2) | (z2 >> 4);
d[count++] = (z2 << 4) | (z3 >> 2);
s+=3;
}
while (BHxlat[ACAST(*s)] != -1)
uuncdl_fulline[leftover++] = *s++;
}
else if (method == YENC_ENCODED) {
while (*s) {
if (*s == '=') {
if (*++s != '\0') {
d[count++] = (char) ((int) *s - 64 - 42);
s++;
}
}
else if (*s == '\n' || *s == '\r') {
s++;
}
else {
d[count++] = (char) ((int) *s++ - 42);
}
}
}
return count;
}
int
UUDecodeQP (FILE *datain, FILE *dataout, int *state,
long maxpos, int method, int flags,
char *boundary)
{
char *line=uugen_inbuffer, *p1, *p2;
int val;
uulboundary = -1;
while (!feof (datain) &&
(ftell(datain)<maxpos || flags&FL_TOEND ||
(!(flags&FL_PROPER) && uu_fast_scanning))) {
if (_FP_fgets (line, 1023, datain) == NULL)
break;
if (ferror (datain)) {
UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
uustring (S_SOURCE_READ_ERR),
strerror (uu_errno = errno));
return UURET_IOERR;
}
line[255] = '\0';
if (boundary && line[0]=='-' && line[1]=='-' &&
strncmp (line+2, boundary, strlen (boundary)) == 0) {
if (line[strlen(boundary)+2]=='-')
uulboundary = 1;
else
uulboundary = 0;
return UURET_OK;
}
if (UUBUSYPOLL(ftell(datain)-progress.foffset,progress.fsize)) {
UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
uustring (S_DECODE_CANCEL));
return UURET_CANCEL;
}
p1 = p2 = line;
while (*p2) {
while (*p2 && *p2 != '=')
p2++;
if (*p2 == '\0')
break;
*p2 = '\0';
fprintf (dataout, "%s", p1);
p1 = ++p2;
if (isxdigit (*p2) && isxdigit (*(p2+1))) {
val = ((isdigit(*p2)) ? (*p2-'0') : (tolower(*p2)-'a'+10)) << 4;
val |= ((isdigit(*(p2+1)))?(*(p2+1)-'0') : (tolower(*(p2+1))-'a'+10));
fputc (val, dataout);
p2 += 2;
p1 = p2;
}
else if (*p2 == '\012' || *(p2+1) == '\015') {
*p2 = '\0';
break;
}
else {
fputc ('=', dataout);
}
}
val = 0;
while (p2>p1 && isspace (*(p2-1))) {
if (*(p2-1) == '\012' || *(p2-1) == '\015')
val = 1;
p2--;
}
*p2 = '\0';
if (val && (!feof (datain) &&
(ftell(datain)<maxpos || flags&FL_TOEND ||
(!(flags&FL_PROPER) && uu_fast_scanning))))
fprintf (dataout, "%s\n", p1);
else
fprintf (dataout, "%s", p1);
}
return UURET_OK;
}
int
UUDecodePT (FILE *datain, FILE *dataout, int *state,
long maxpos, int method, int flags,
char *boundary)
{
char *line=uugen_inbuffer, *ptr;
uulboundary = -1;
while (!feof (datain) &&
(ftell(datain)<maxpos || flags&FL_TOEND ||
(!(flags&FL_PROPER) && uu_fast_scanning))) {
if (_FP_fgets (line, 1023, datain) == NULL)
break;
if (ferror (datain)) {
UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
uustring (S_SOURCE_READ_ERR),
strerror (uu_errno = errno));
return UURET_IOERR;
}
line[255] = '\0';
if (boundary && line[0]=='-' && line[1]=='-' &&
strncmp (line+2, boundary, strlen (boundary)) == 0) {
if (line[strlen(boundary)+2]=='-')
uulboundary = 1;
else
uulboundary = 0;
return UURET_OK;
}
if (UUBUSYPOLL(ftell(datain)-progress.foffset,progress.fsize)) {
UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
uustring (S_DECODE_CANCEL));
return UURET_CANCEL;
}
ptr = line + strlen (line);
while (ptr>line && (*(ptr-1) == '\012' || *(ptr-1) == '\015'))
ptr--;
if ((*ptr == '\012' || *ptr == '\015') &&
(ftell(datain)<maxpos || flags&FL_TOEND || flags&FL_PARTIAL ||
!boundary || (!(flags&FL_PROPER) && uu_fast_scanning))) {
*ptr = '\0';
fprintf (dataout, "%s\n", line);
}
else {
*ptr = '\0';
fprintf (dataout, "%s", line);
}
}
return UURET_OK;
}
int
UUDecodeField (char *s, char *d, int method)
{
int z1, z2, z3, z4;
int count=0;
if (method == B64ENCODED) {
while ((z1 = B64xlat[ACAST(*s)]) != -1) {
if ((z2 = B64xlat[ACAST(*(s+1))]) == -1) break;
if ((z3 = B64xlat[ACAST(*(s+2))]) == -1) break;
if ((z4 = B64xlat[ACAST(*(s+3))]) == -1) break;
d[count++] = (z1 << 2) | (z2 >> 4);
d[count++] = (z2 << 4) | (z3 >> 2);
d[count++] = (z3 << 6) | (z4);
s+=4;
}
if (z1 != -1 && z2 != -1 && *(s+2) == '=') {
d[count++] = (z1 << 2) | (z2 >> 4);
s+=2;
}
else if (z1 != -1 && z2 != -1 && z3 != -1 && *(s+3) == '=') {
d[count++] = (z1 << 2) | (z2 >> 4);
d[count++] = (z2 << 4) | (z3 >> 2);
s+=3;
}
}
else if (method == QP_ENCODED) {
while (*s && (*s != '?' || *(s+1) != '=')) {
while (*s && *s != '=' && (*s != '?' || *(s+1) != '=')) {
d[count++] = *s++;
}
if (*s == '=') {
if (isxdigit (*(s+1)) && isxdigit (*(s+2))) {
d[count] = (isdigit (*(s+1)) ? (*(s+1)-'0') : (tolower (*(s+1))-'a'+10)) << 4;
d[count] |= (isdigit (*(s+2)) ? (*(s+2)-'0') : (tolower (*(s+2))-'a'+10));
count++;
s+=3;
}
else if (*(s+1) == '\012' || *(s+1) == '\015') {
s+=2;
}
else {
d[count++] = *s++;
}
}
}
}
else {
return -1;
}
d[count] = '\0';
return count;
}
int
UUDecodePart (FILE *datain, FILE *dataout, int *state,
long maxpos, int method, int flags,
char *boundary)
{
char *line, *oline=uuncdp_oline;
int warning=0, vlc=0, lc[2], hadct=0;
int tc=0, tf=0, vflag, haddata=0, haddh=0;
long yefilesize=0, yepartends=0;
crc32_t yepartcrc=crc32(0L, Z_NULL, 0);
static crc32_t yefilecrc=0;
static int bhflag=0;
size_t count=0;
size_t yepartsize=0;
char *ptr;
if (datain == NULL || dataout == NULL) {
yefilecrc = crc32(0L, Z_NULL, 0);
bhflag = 0;
return UURET_OK;
}
if (method == QP_ENCODED)
return UUDecodeQP (datain, dataout, state, maxpos,
method, flags, boundary);
else if (method == PT_ENCODED)
return UUDecodePT (datain, dataout, state, maxpos,
method, flags, boundary);
lc[0] = lc[1] = 0;
vflag = 0;
uulboundary = -1;
if (method == YENC_ENCODED) {
*state = BEGIN;
}
while (!feof (datain) && *state != DONE &&
(ftell(datain)<maxpos || flags&FL_TOEND || maxpos==-1 ||
(!(flags&FL_PROPER) && uu_fast_scanning))) {
if (_FP_fgets ((line = uugen_fnbuffer), 1200 - 5, datain) == NULL)
break;
if (*line == '.' && uu_dotdot)
line++;
if (ferror (datain)) {
UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
uustring (S_SOURCE_READ_ERR),
strerror (uu_errno = errno));
return UURET_IOERR;
}
if (line[0]=='\015' || line[0]=='\012') {
if (*state == DATA &&
(method == UU_ENCODED || method == XX_ENCODED))
*state = END;
if (vlc > 5)
tf = tc = 0;
vlc = 0;
continue;
}
if (UUBUSYPOLL(ftell(datain)-progress.foffset,progress.fsize)) {
UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
uustring (S_DECODE_CANCEL));
return UURET_CANCEL;
}
line[1200 - 1] = '\0';
count = 0;
if (boundary && line[0]=='-' && line[1]=='-' &&
strncmp (line+2, boundary, strlen (boundary)) == 0) {
if (line[strlen(boundary)+2]=='-')
uulboundary = 1;
else
uulboundary = 0;
return UURET_OK;
}
if ((flags&FL_PROPER) == 0) {
if (strncmp (line, "BEGIN", 5) == 0 &&
_FP_strstr (line, "CUT HERE") && !tf) {
tc = tf = vlc = 0;
continue;
}
if (line[0] == '-' && line[1] == '-' && method == B64ENCODED) {
if ((haddata || tc) && (haddh || hadct)) {
*state = DONE;
vlc = 0;
lc[0] = lc[1] = 0;
continue;
}
hadct = 0;
haddh = 1;
continue;
}
if (_FP_strnicmp (line, "Content-Type", 12) == 0)
hadct = 1;
}
if (*state == BEGIN) {
if ((method == UU_ENCODED || method == XX_ENCODED) &&
(strncmp (line, "begin ", 6) == 0 ||
_FP_strnicmp (line, "<pre>begin ", 11) == 0)) {
*state = DATA;
continue;
}
else if (method == BH_ENCODED && line[0] == ':') {
if (UUValidData (line, BH_ENCODED, &bhflag) == BH_ENCODED) {
bhflag = 0;
*state = DATA;
}
else
continue;
}
else if (method == YENC_ENCODED &&
strncmp (line, "=ybegin ", 8) == 0 &&
_FP_strstr (line, " name=") != NULL) {
*state = DATA;
if ((ptr = _FP_strstr (line, " size=")) != NULL) {
ptr += 6;
yefilesize = atoi (ptr);
}
else {
yefilesize = -1;
}
if (_FP_strstr (line, " part=") != NULL) {
if (_FP_fgets (line, 1200 - 5, datain) == NULL) {
break;
}
if ((ptr = _FP_strstr (line, " end=")) == NULL) {
break;
}
yepartends = atoi (ptr + 5);
}
tf = 1;
continue;
}
else {
continue;
}
tc = tf = vlc = 0;
lc[0] = lc[1] = 0;
}
else if ((*state == END) &&
(method == UU_ENCODED || method == XX_ENCODED)) {
if (strncmp (line, "end", 3) == 0) {
*state = DONE;
break;
}
}
if (*state == DATA && method == YENC_ENCODED &&
strncmp (line, "=yend ", 6) == 0) {
if ((ptr = _FP_strstr (line, " pcrc32=")) != NULL) {
crc32_t pcrc32 = strtoul (ptr + 8, NULL, 16);
if (pcrc32 != yepartcrc) {
UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
uustring (S_PCRC_MISMATCH), progress.curfile, progress.partno);
}
}
if ((ptr = _FP_strstr (line, " crc32=")) != NULL)
{
crc32_t fcrc32 = strtoul (ptr + 7, NULL, 16);
if (fcrc32 != yefilecrc) {
UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
uustring (S_CRC_MISMATCH), progress.curfile);
}
}
if ((ptr = _FP_strstr (line, " size=")) != NULL)
{
size_t size = atol(ptr + 6);
if (size != yepartsize && yefilesize != -1) {
if (size != yefilesize)
UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
uustring (S_PSIZE_MISMATCH), progress.curfile,
progress.partno, yepartsize, size);
else
UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
uustring (S_SIZE_MISMATCH), progress.curfile,
yepartsize, size);
}
}
if (yepartends == 0 || yepartends >= yefilesize) {
*state = DONE;
}
break;
}
if (*state == DATA || *state == END) {
if (method==B64ENCODED && line[0]=='-' && line[1]=='-' && tc) {
break;
}
if ((vflag = UUValidData (line, (tf)?method:0, &bhflag)) == 0)
vflag = UURepairData (datain, line, (tf)?method:0, &bhflag);
if ((method == XX_ENCODED || method == UU_ENCODED) &&
vflag == B64ENCODED) {
if (UUValidData (line, method, &bhflag) == method)
vflag = method;
}
if (vflag == method) {
if (tf) {
count = UUDecodeLine (line, oline, method);
if (method == YENC_ENCODED) {
if (yepartends)
yepartcrc = crc32(yepartcrc, oline, count);
yefilecrc = crc32(yefilecrc, oline, count);
yepartsize += count;
}
vlc++; lc[1]++;
}
else if (tc == 3) {
count = UUDecodeLine (save[0], oline, method);
count += UUDecodeLine (save[1], oline + count, method);
count += UUDecodeLine (save[2], oline + count, method);
count += UUDecodeLine (line, oline + count, method);
tf = 1;
tc = 0;
if (lc[1] > 10 && (lc[0] >= 1 && lc[0] <= 2) && !warning) {
UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
uustring (S_DATA_SUSPICIOUS));
warning=1;
}
lc[0] = 0;
lc[1] = 3;
}
else {
_FP_strncpy (save[tc++], line, 1200);
}
if (method == UU_ENCODED)
*state = (line[0] == 'M') ? DATA : END;
else if (method == XX_ENCODED)
*state = (line[0] == 'h') ? DATA : END;
else if (method == B64ENCODED)
*state = (strchr (line, '=') == NULL) ? DATA : DONE;
else if (method == BH_ENCODED)
*state = (!line[0] || strchr(line+1,':')==NULL)?DATA:DONE;
}
else {
vlc = tf = tc = 0;
haddh = 0;
lc[0]++;
}
}
else if (*state != DONE) {
return UURET_NOEND;
}
if (count) {
if (method == BH_ENCODED) {
if (UUbhwrite (oline, 1, count, dataout) != count) {
UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
uustring (S_WR_ERR_TEMP),
strerror (uu_errno = errno));
return UURET_IOERR;
}
}
else if (fwrite (oline, 1, count, dataout) != count) {
UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
uustring (S_WR_ERR_TEMP),
strerror (uu_errno = errno));
return UURET_IOERR;
}
haddata++;
count = 0;
}
}
if (*state == DONE ||
(*state == DATA && method == B64ENCODED &&
vflag == B64ENCODED && (flags&FL_PROPER || haddh))) {
for (tf=0; tf<tc; tf++)
count += UUDecodeLine (save[tf], oline + count, method);
if (count) {
if (method == BH_ENCODED) {
if (UUbhwrite (oline, 1, count, dataout) != count) {
UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
uustring (S_WR_ERR_TEMP),
strerror (uu_errno = errno));
return UURET_IOERR;
}
}
else if (fwrite (oline, 1, count, dataout) != count) {
UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
uustring (S_WR_ERR_TEMP),
strerror (uu_errno = errno));
return UURET_IOERR;
}
}
}
return UURET_OK;
}
int
UUDecode (uulist *data)
{
int state=BEGIN, part=-1, res=0, hb;
long rsize, dsize, numbytes;
FILE *datain, *dataout;
unsigned char r[8];
char *mode, *ntmp;
uufile *iter;
size_t bytes;
#ifdef HAVE_MKSTEMP
int tmpfd;
const char *tmpprefix = "uuXXXXXX";
char *tmpdir = NULL;
#endif
if (data == NULL || data->thisfile == NULL)
return UURET_ILLVAL;
if (data->state & UUFILE_TMPFILE)
return UURET_OK;
if (data->state & UUFILE_NODATA)
return UURET_NODATA;
if (data->state & UUFILE_NOBEGIN && !uu_desperate)
return UURET_NODATA;
if (data->uudet == PT_ENCODED)
mode = "wt";
else
mode = "wb";
#ifdef HAVE_MKSTEMP
if ((getuid()==geteuid()) && (getgid()==getegid())) {
tmpdir=getenv("TMPDIR");
}
if (!tmpdir) {
tmpdir = "/tmp";
}
data->binfile = malloc(strlen(tmpdir)+strlen(tmpprefix)+2);
if (!data->binfile) {
#else
if ((data->binfile = tempnam (NULL, "uu")) == NULL) {
#endif
UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
uustring (S_NO_TEMP_NAME));
return UURET_NOMEM;
}
#ifdef HAVE_MKSTEMP
strcpy(data->binfile, tmpdir);
strcat(data->binfile, "/");
strcat(data->binfile, tmpprefix);
if ((tmpfd = mkstemp(data->binfile)) == -1 ||
(dataout = fdopen(tmpfd, mode)) == NULL) {
#else
if ((dataout = fopen (data->binfile, mode)) == NULL) {
#endif
UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
uustring (S_WR_ERR_TARGET),
data->binfile, strerror (uu_errno = errno));
#ifdef HAVE_MKSTEMP
if (tmpfd != -1) {
unlink(data->binfile);
close(tmpfd);
}
#endif
_FP_free (data->binfile);
data->binfile = NULL;
uu_errno = errno;
return UURET_IOERR;
}
if (data->uudet == B64ENCODED || data->uudet == QP_ENCODED ||
data->uudet == PT_ENCODED)
state = DATA;
if ((data->state & UUFILE_NOBEGIN) && uu_desperate)
state = DATA;
(void) UUDecodeLine (NULL, NULL, 0);
(void) UUbhwrite (NULL, 0, 0, NULL);
(void) UUDecodePart (NULL, NULL, NULL, 0, 0, 0, NULL);
progress.action = 0;
if (data->filename != NULL) {
_FP_strncpy (progress.curfile,
(strlen(data->filename)>255)?
(data->filename+strlen(data->filename)-255):data->filename,
256);
}
else {
_FP_strncpy (progress.curfile,
(strlen(data->binfile)>255)?
(data->binfile+strlen(data->binfile)-255):data->binfile,
256);
}
progress.partno = 0;
progress.numparts = 0;
progress.fsize = -1;
progress.percent = 0;
progress.action = UUACT_DECODING;
iter = data->thisfile;
while (iter) {
progress.numparts = (iter->partno)?iter->partno:1;
iter = iter->NEXT;
}
iter = data->thisfile;
while (iter) {
if (part != -1 && iter->partno != part+1 && !uu_desperate)
break;
else
part = iter->partno;
if (iter->data->sfname == NULL) {
iter = iter->NEXT;
continue;
}
if (uu_FileCallback) {
if ((res = (*uu_FileCallback) (uu_FileCBArg, iter->data->sfname,
uugen_fnbuffer, 1)) != UURET_OK)
break;
if ((datain = fopen (uugen_fnbuffer, "rb")) == NULL) {
(*uu_FileCallback) (uu_FileCBArg, iter->data->sfname,
uugen_fnbuffer, 0);
UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
uustring (S_NOT_OPEN_FILE),
uugen_fnbuffer, strerror (uu_errno = errno));
res = UURET_IOERR;
break;
}
}
else {
if ((datain = fopen (iter->data->sfname, "rb")) == NULL) {
UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
uustring (S_NOT_OPEN_FILE),
iter->data->sfname, strerror (uu_errno = errno));
res = UURET_IOERR;
break;
}
_FP_strncpy (uugen_fnbuffer, iter->data->sfname, 1024);
}
progress.partno = part;
progress.fsize = (iter->data->length)?iter->data->length:-1;
progress.percent = 0;
progress.foffset = iter->data->startpos;
fseek (datain, iter->data->startpos, SEEK_SET);
res = UUDecodePart (datain, dataout, &state,
iter->data->startpos+iter->data->length,
data->uudet, iter->data->flags, NULL);
fclose (datain);
if (uu_FileCallback)
(*uu_FileCallback) (uu_FileCBArg, iter->data->sfname, uugen_fnbuffer, 0);
if (state == DONE || res != UURET_OK)
break;
iter = iter->NEXT;
}
if (state == DATA &&
(data->uudet == B64ENCODED || data->uudet == QP_ENCODED ||
data->uudet == PT_ENCODED))
state = DONE;
if (fclose (dataout)) {
UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
uustring (S_WR_ERR_TEMP),
strerror (uu_errno = errno));
res = UURET_IOERR;
}
if (res != UURET_OK || (state != DONE && !uu_desperate)) {
unlink (data->binfile);
_FP_free (data->binfile);
data->binfile = NULL;
data->state &= ~UUFILE_TMPFILE;
data->state |= UUFILE_ERROR;
if (res == UURET_OK && state != DONE)
res = UURET_NOEND;
}
else if (res != UURET_OK) {
data->state &= ~UUFILE_DECODED;
data->state |= UUFILE_ERROR | UUFILE_TMPFILE;
}
else {
data->state &= ~UUFILE_ERROR;
data->state |= UUFILE_TMPFILE;
}
if (data->uudet == BH_ENCODED && data->binfile) {
#ifdef HAVE_MKSTEMP
ntmp = malloc(strlen(tmpdir)+strlen(tmpprefix)+2);
if (ntmp == NULL) {
#else
if ((ntmp = tempnam (NULL, "uu")) == NULL) {
#endif
UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
uustring (S_NO_TEMP_NAME));
progress.action = 0;
return UURET_NOMEM;
}
if ((datain = fopen (data->binfile, "rb")) == NULL) {
UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
uustring (S_NOT_OPEN_FILE),
data->binfile, strerror (uu_errno = errno));
progress.action = 0;
free (ntmp);
return UURET_IOERR;
}
#ifdef HAVE_MKSTEMP
strcpy(ntmp, tmpdir);
strcat(ntmp, "/");
strcat(ntmp, tmpprefix);
if ((tmpfd = mkstemp(ntmp)) == -1 ||
(dataout = fdopen(tmpfd, "wb")) == NULL) {
#else
if ((dataout = fopen (ntmp, "wb")) == NULL) {
#endif
UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
uustring (S_NOT_OPEN_TARGET),
ntmp, strerror (uu_errno = errno));
progress.action = 0;
fclose (datain);
#ifdef HAVE_MKSTEMP
if (tmpfd != -1) {
unlink(ntmp);
close(tmpfd);
}
#endif
free (ntmp);
return UURET_IOERR;
}
r[0] = fgetc (datain);
hb = (int) r[0] + 22;
fseek (datain, (int) r[0] + 12, SEEK_SET);
fread (r, 1, 8, datain);
dsize = (((long) 1 << 24) * (long) r[0]) +
(((long) 1 << 16) * (long) r[1]) +
(((long) 1 << 8) * (long) r[2]) +
( (long) r[3]);
rsize = (((long) 1 << 24) * (long) r[4]) +
(((long) 1 << 16) * (long) r[5]) +
(((long) 1 << 8) * (long) r[6]) +
( (long) r[7]);
UUMessage (uunconc_id, __LINE__, UUMSG_MESSAGE,
uustring (S_BINHEX_SIZES),
dsize, rsize);
if (dsize == 0) {
fseek (datain, dsize + hb + 2, SEEK_SET);
numbytes = rsize;
}
else if (rsize == 0) {
fseek (datain, hb, SEEK_SET);
numbytes = dsize;
}
else {
UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
uustring (S_BINHEX_BOTH));
fseek (datain, hb, SEEK_SET);
numbytes = dsize;
}
progress.action = 0;
progress.partno = 0;
progress.numparts = 1;
progress.fsize = (numbytes)?numbytes:-1;
progress.foffset = hb;
progress.percent = 0;
progress.action = UUACT_COPYING;
while (!feof (datain) && numbytes) {
if (UUBUSYPOLL(ftell(datain)-progress.foffset,progress.fsize)) {
UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
uustring (S_DECODE_CANCEL));
fclose (datain);
fclose (dataout);
unlink (ntmp);
free (ntmp);
return UURET_CANCEL;
}
bytes = fread (uugen_inbuffer, 1,
(size_t) ((numbytes>1024)?1024:numbytes), datain);
if (ferror (datain) || (bytes == 0 && !feof (datain))) {
progress.action = 0;
UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
uustring (S_SOURCE_READ_ERR),
data->binfile, strerror (uu_errno = errno));
fclose (datain);
fclose (dataout);
unlink (ntmp);
free (ntmp);
return UURET_IOERR;
}
if (fwrite (uugen_inbuffer, 1, bytes, dataout) != bytes) {
progress.action = 0;
UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
uustring (S_WR_ERR_TARGET),
ntmp, strerror (uu_errno = errno));
fclose (datain);
fclose (dataout);
unlink (ntmp);
free (ntmp);
return UURET_IOERR;
}
numbytes -= bytes;
}
if (numbytes) {
UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
uustring (S_SHORT_BINHEX),
(data->filename)?data->filename:
(data->subfname)?data->subfname:"???",
numbytes);
}
fclose (datain);
if (fclose (dataout)) {
UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
uustring (S_WR_ERR_TARGET),
ntmp, strerror (uu_errno = errno));
unlink (ntmp);
free (ntmp);
return UURET_IOERR;
}
if (unlink (data->binfile)) {
UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
uustring (S_TMP_NOT_REMOVED),
data->binfile, strerror (uu_errno = errno));
}
free (data->binfile);
data->binfile = ntmp;
}
progress.action = 0;
return res;
}
int
UUQuickDecode (FILE *datain, FILE *dataout, char *boundary, long maxpos)
{
int state=BEGIN, encoding=-1;
headers myenv;
memset (&myenv, 0, sizeof (headers));
UUScanHeader (datain, &myenv);
if (_FP_stristr (myenv.ctenc, "uu") != NULL)
encoding = UU_ENCODED;
else if (_FP_stristr (myenv.ctenc, "xx") != NULL)
encoding = XX_ENCODED;
else if (_FP_stricmp (myenv.ctenc, "base64") == 0)
encoding = B64ENCODED;
else if (_FP_stricmp (myenv.ctenc, "quoted-printable") == 0)
encoding = QP_ENCODED;
else
encoding = PT_ENCODED;
UUkillheaders (&myenv);
(void) UUDecodePart (NULL, NULL, NULL, 0, 0, 0, NULL);
return UUDecodePart (datain, dataout, &state, maxpos,
encoding, FL_PROPER|FL_TOEND,
boundary);
}