2000-02-25 10:15:17 +00:00
|
|
|
/*
|
|
|
|
* This file is part of uudeview, the simple and friendly multi-part multi-
|
2001-11-01 17:20:18 +00:00
|
|
|
* file uudecoder program (c) 1994-2001 by Frank Pilhofer. The author may
|
|
|
|
* be contacted at fp@fpx.de
|
2000-02-25 10:15:17 +00:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef SYSTEM_WINDLL
|
|
|
|
#include <windows.h>
|
|
|
|
#endif
|
|
|
|
#ifdef SYSTEM_OS2
|
|
|
|
#include <os2.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* uucheck.c
|
|
|
|
*
|
|
|
|
* Various checking and processing of one input part
|
|
|
|
**/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
#ifdef STDC_HEADERS
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_MALLOC_H
|
|
|
|
#include <malloc.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_MEMORY_H
|
|
|
|
#include <memory.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <uudeview.h>
|
|
|
|
#include <uuint.h>
|
|
|
|
#include <fptools.h>
|
|
|
|
#include <uustring.h>
|
|
|
|
|
|
|
|
char * uucheck_id = "$Id$";
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Arbitrary number. This is the maximum number of part numbers we
|
|
|
|
* store for our have-parts and missing-parts lists
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define MAXPLIST 256
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* forward declarations of local functions
|
|
|
|
*/
|
|
|
|
|
|
|
|
static char * UUGetFileName _ANSI_ARGS_((char *, char *, char *));
|
|
|
|
static int UUGetPartNo _ANSI_ARGS_((char *, char **, char **));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* State of Scanner function and PreProcessPart
|
|
|
|
*/
|
|
|
|
|
|
|
|
int lastvalid, lastenc, nofnum;
|
|
|
|
char *uucheck_lastname;
|
|
|
|
char *uucheck_tempname;
|
|
|
|
static int lastpart = 0;
|
|
|
|
static char *nofname = "UNKNOWN";
|
|
|
|
|
|
|
|
/*
|
|
|
|
* special characters we allow an unquoted filename to have
|
|
|
|
*/
|
|
|
|
|
|
|
|
static char *fnchars = "._-~!";
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Policy for extracting a part number from the subject line.
|
|
|
|
* usually, look for part numbers in () brackets first, then in []
|
|
|
|
*/
|
|
|
|
|
|
|
|
static char *brackchr[] = {
|
|
|
|
"()[]", "[]()"
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Extract a filename from the subject line. We need anything to identify
|
|
|
|
* the name of the program for sorting. If a nice filename cannot be found,
|
|
|
|
* the subject line itself is used
|
|
|
|
* ptonum is, if not NULL, a pointer to the part number in the subject line,
|
|
|
|
* so that it won't be used as filename.
|
|
|
|
**/
|
|
|
|
|
|
|
|
static char *
|
|
|
|
UUGetFileName (char *subject, char *ptonum, char *ptonend)
|
|
|
|
{
|
|
|
|
char *ptr = subject, *iter, *result, *part;
|
|
|
|
int count, length=0, alflag=0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If this file has no subject line, assume it is the next part of the
|
|
|
|
* previous file (this is done in UUPreProcessPart)
|
|
|
|
**/
|
|
|
|
|
|
|
|
if (subject == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the subject starts with 'Re', it is ignored
|
|
|
|
* REPosts or RETries are not ignored!
|
|
|
|
**/
|
|
|
|
|
|
|
|
if (uu_ignreply &&
|
|
|
|
(subject[0] == 'R' || subject[0] == 'r') &&
|
|
|
|
(subject[1] == 'E' || subject[1] == 'e') &&
|
|
|
|
(subject[2] == ':' || subject[2] == ' ')) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Ignore a "Repost" prefix of the subject line. We don't want to get
|
|
|
|
* a file named "Repost" :-)
|
|
|
|
**/
|
|
|
|
|
|
|
|
if (_FP_strnicmp (subject, "repost", 6) == 0)
|
|
|
|
subject += 6;
|
|
|
|
if (_FP_strnicmp (subject, "re:", 3) == 0)
|
|
|
|
subject += 3;
|
|
|
|
|
|
|
|
while (*subject == ' ' || *subject == ':') subject++;
|
|
|
|
|
|
|
|
part = _FP_stristr (subject, "part");
|
|
|
|
if (part == subject) {
|
|
|
|
subject += 4;
|
|
|
|
while (*subject == ' ') subject++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the file was encoded by uuenview, then the filename is enclosed
|
|
|
|
* in [brackets]. But check what's inside these bracket's, try not to
|
|
|
|
* fall for something other than a filename
|
|
|
|
*/
|
|
|
|
|
|
|
|
ptr = subject;
|
|
|
|
while ((iter = strchr (ptr, '[')) != NULL) {
|
|
|
|
if (strchr (iter, ']') == NULL) {
|
|
|
|
ptr = iter + 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
iter++;
|
|
|
|
while (isspace (*iter))
|
|
|
|
iter++;
|
|
|
|
count = length = alflag = 0;
|
|
|
|
while (iter[count] &&
|
|
|
|
(isalnum (iter[count]) || strchr (fnchars, iter[count])!=NULL)) {
|
|
|
|
if (isalpha (iter[count]))
|
|
|
|
alflag++;
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
if (count<4 || alflag==0) {
|
|
|
|
ptr = iter + 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
length = count;
|
|
|
|
while (isspace (iter[count]))
|
|
|
|
count++;
|
|
|
|
if (iter[count] == ']') {
|
|
|
|
ptr = iter;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
length = 0;
|
|
|
|
ptr = iter + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* new filename detection routine, fists mostly for files by ftp-by-email
|
|
|
|
* servers that create subject lines with ftp.host.address:/full/path/file
|
|
|
|
* on them. We look for slashes and take the filename from after the last
|
|
|
|
* one ... or at least we try to.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (length == 0) {
|
|
|
|
ptr = subject;
|
|
|
|
while ((iter = strchr (ptr, '/')) != NULL) {
|
|
|
|
if (iter >= ptonum && iter <= ptonend) {
|
|
|
|
ptr = iter + 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
count = length = 0;
|
|
|
|
iter++;
|
|
|
|
while (iter[count] &&
|
|
|
|
(isalnum(iter[count])||strchr(fnchars, iter[count])!=NULL))
|
|
|
|
count++;
|
|
|
|
if (iter[count] == ' ' && length > 4) {
|
|
|
|
length = count;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ptr = iter + ((count)?count:1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Look for two alphanumeric strings separated by a '.'
|
|
|
|
* (That's most likely a filename)
|
|
|
|
**/
|
|
|
|
|
|
|
|
if (length == 0) {
|
|
|
|
ptr = subject;
|
|
|
|
while (*ptr && *ptr != 0x0a && *ptr != 0x0d && ptr != part) {
|
|
|
|
iter = ptr;
|
|
|
|
count = length = alflag = 0;
|
|
|
|
|
|
|
|
if (_FP_strnicmp (ptr, "ftp", 3) == 0) {
|
|
|
|
/* hey, that's an ftp address */
|
|
|
|
while (isalpha (*ptr) || isdigit (*ptr) || *ptr == '.')
|
|
|
|
ptr++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
while ((isalnum(*iter)||strchr(fnchars, *iter)!=NULL||
|
|
|
|
*iter=='/') && *iter && iter != ptonum && *iter != '.') {
|
|
|
|
if (isalpha (*iter))
|
|
|
|
alflag = 1;
|
|
|
|
|
|
|
|
count++; iter++;
|
|
|
|
}
|
|
|
|
if (*iter == '\0' || iter == ptonum) {
|
|
|
|
if (iter == ptonum)
|
|
|
|
ptr = ptonend;
|
|
|
|
else
|
|
|
|
ptr = iter;
|
|
|
|
|
|
|
|
length = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (*iter++ != '.' || count > 32 || alflag == 0) {
|
|
|
|
ptr = iter;
|
|
|
|
length = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (_FP_strnicmp (iter, "edu", 3) == 0 ||
|
|
|
|
_FP_strnicmp (iter, "gov", 3) == 0) {
|
|
|
|
/* hey, that's an ftp address */
|
|
|
|
while (isalpha (*iter) || isdigit (*iter) || *iter == '.')
|
|
|
|
iter++;
|
|
|
|
ptr = iter;
|
|
|
|
length = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
length += count + 1;
|
|
|
|
count = 0;
|
|
|
|
|
|
|
|
while ((isalnum(iter[count])||strchr(fnchars, iter[count])!=NULL||
|
|
|
|
iter[count]=='/') && iter[count] && iter[count] != '.')
|
|
|
|
count++;
|
|
|
|
|
|
|
|
if (iter[count]==':' && iter[count+1]=='/') {
|
|
|
|
/* looks like stuff from a mail server */
|
|
|
|
ptr = iter + 1;
|
|
|
|
length = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count > 8 || iter == ptonum) {
|
|
|
|
ptr = iter;
|
|
|
|
length = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (iter[count] != '.') {
|
|
|
|
length += count;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (iter[count] &&
|
|
|
|
(isalnum(iter[count])||strchr(fnchars, iter[count])!=NULL||
|
|
|
|
iter[count]=='/'))
|
|
|
|
count++;
|
|
|
|
|
|
|
|
if (iter[count]==':' && iter[count+1]=='/') {
|
|
|
|
/* looks like stuff from a mail server */
|
|
|
|
ptr = iter + 1;
|
|
|
|
length = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count < 12 && iter != ptonum) {
|
|
|
|
length += count;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = iter;
|
|
|
|
length = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (length == 0) { /* No filename found, use subject line for ident */
|
|
|
|
ptr = subject;
|
|
|
|
|
|
|
|
while (*ptr && !isalpha (*ptr))
|
|
|
|
ptr++;
|
|
|
|
|
|
|
|
while ((isalnum(ptr[length])||strchr(fnchars,ptr[length])!=NULL||
|
|
|
|
ptr[length] == '/') &&
|
|
|
|
ptr[length] && ptr+length!=part && ptr+length!=ptonum)
|
|
|
|
length++;
|
|
|
|
|
|
|
|
if (length) {
|
|
|
|
if (ptr[length] == '\0' || ptr[length] == 0x0a || ptr[length] == 0x0d) {
|
|
|
|
length--;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* I used to cut off digits from the end of the string, but
|
|
|
|
* let's try to live without. We want to distinguish
|
|
|
|
* DUTCH951 from DUTCH952
|
|
|
|
*
|
|
|
|
* while ((ptr[length] == ' ' || isdigit (ptr[length])) && length > 0)
|
|
|
|
* length--;
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
length--;
|
|
|
|
|
|
|
|
while (ptr[length] == ' ' && length > 0)
|
|
|
|
length--;
|
|
|
|
}
|
|
|
|
length++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (length == 0) { /* Still found nothing? We need *something*! */
|
|
|
|
ptr = nofname;
|
|
|
|
length = strlen (nofname);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((result = (char *) malloc (length + 1)) == NULL) {
|
|
|
|
UUMessage (uucheck_id, __LINE__, UUMSG_ERROR,
|
|
|
|
uustring (S_OUT_OF_MEMORY), length+1);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy (result, ptr, length);
|
|
|
|
result[length] = '\0';
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Extract the Part Number from the subject line.
|
|
|
|
* We look first for numbers in (#/#)'s, then for numbers in [#/#]'s
|
|
|
|
* and then for digits that are not part of a string.
|
|
|
|
* If we cannot find anything, assume it is the next part of the
|
|
|
|
* previous file.
|
|
|
|
* If we find a part number, we put a pointer to it in *where. This is
|
|
|
|
* done so that the UUGetFileName function doesn't accidentally use the
|
|
|
|
* part number as the file name. *whend points to the end of this part
|
|
|
|
* number.
|
|
|
|
**/
|
|
|
|
|
|
|
|
static int
|
|
|
|
UUGetPartNo (char *subject, char **where, char **whend)
|
|
|
|
{
|
|
|
|
char *ptr = subject, *iter, *delim, bdel[2]=" ";
|
|
|
|
int count, length=0, bpc;
|
|
|
|
|
|
|
|
*where = NULL; bdel[0] = ' ';
|
|
|
|
*whend = NULL; bdel[1] = '\0';
|
|
|
|
|
|
|
|
iter = NULL;
|
|
|
|
delim = "";
|
|
|
|
|
|
|
|
if (subject == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (uu_ignreply &&
|
|
|
|
(subject[0] == 'R' || subject[0] == 'r') && /* Ignore replies, but not */
|
|
|
|
(subject[1] == 'E' || subject[1] == 'e') && /* reposts */
|
|
|
|
(subject[2] == ':' || subject[2] == ' '))
|
|
|
|
return -2;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* First try numbers in () or [] (or vice versa, according to bracket
|
|
|
|
* policy)
|
|
|
|
*/
|
|
|
|
|
|
|
|
for (bpc=0, length=0; brackchr[uu_bracket_policy][bpc]; bpc+=2) {
|
|
|
|
ptr = subject;
|
|
|
|
while ((iter = strchr (ptr, brackchr[uu_bracket_policy][bpc])) != NULL) {
|
|
|
|
count = length = 0; iter++;
|
|
|
|
|
|
|
|
while (*iter == ' ' || *iter == '#')
|
|
|
|
iter++;
|
|
|
|
|
|
|
|
if (!isdigit (*iter)) {
|
|
|
|
ptr = iter;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
while (isdigit (iter[count]))
|
|
|
|
count++;
|
|
|
|
length = count;
|
|
|
|
|
|
|
|
if (iter[count] == '\0' || iter[count+1] == '\0') {
|
|
|
|
iter += count;
|
|
|
|
length = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (iter[count] == brackchr[uu_bracket_policy][bpc+1]) {
|
|
|
|
*where = iter;
|
|
|
|
bdel[0] = brackchr[uu_bracket_policy][bpc+1];
|
|
|
|
delim = bdel;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (iter[count] == ' ' || iter[count] == '#' ||
|
|
|
|
iter[count] == '/' || iter[count] == '\\') count++;
|
|
|
|
|
|
|
|
if (_FP_strnicmp (iter + count, "of", 2) == 0)
|
|
|
|
count += 2;
|
|
|
|
|
|
|
|
while (iter[count] == ' ') count++;
|
|
|
|
while (isdigit (iter[count])) count++;
|
|
|
|
while (iter[count] == ' ') count++;
|
|
|
|
|
|
|
|
if (iter[count] == brackchr[uu_bracket_policy][bpc+1]) {
|
|
|
|
*where = iter;
|
|
|
|
bdel[0] = brackchr[uu_bracket_policy][bpc+1];
|
|
|
|
delim = bdel;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
length = 0;
|
|
|
|
ptr = iter;
|
|
|
|
}
|
|
|
|
if (length)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* look for the string "part " followed by a number
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (length == 0) {
|
|
|
|
if ((iter = _FP_stristr (subject, "part ")) != NULL) {
|
|
|
|
iter += 5;
|
|
|
|
|
|
|
|
while (isspace (*iter) || *iter == '.' || *iter == '-')
|
|
|
|
iter++;
|
|
|
|
|
|
|
|
while (isdigit (iter[length]))
|
|
|
|
length++;
|
|
|
|
|
|
|
|
if (length == 0) {
|
|
|
|
if (_FP_strnicmp (iter, "one", 3) == 0) length = 1;
|
|
|
|
else if (_FP_strnicmp (iter, "two", 3) == 0) length = 2;
|
|
|
|
else if (_FP_strnicmp (iter, "three", 5) == 0) length = 3;
|
|
|
|
else if (_FP_strnicmp (iter, "four", 4) == 0) length = 4;
|
|
|
|
else if (_FP_strnicmp (iter, "five", 4) == 0) length = 5;
|
|
|
|
else if (_FP_strnicmp (iter, "six", 3) == 0) length = 6;
|
|
|
|
else if (_FP_strnicmp (iter, "seven", 5) == 0) length = 7;
|
|
|
|
else if (_FP_strnicmp (iter, "eight", 5) == 0) length = 8;
|
|
|
|
else if (_FP_strnicmp (iter, "nine", 4) == 0) length = 9;
|
|
|
|
else if (_FP_strnicmp (iter, "ten", 3) == 0) length = 10;
|
|
|
|
|
|
|
|
if (length && (*whend = strchr (iter, ' '))) {
|
|
|
|
*where = iter;
|
|
|
|
return length;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
length = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*where = iter;
|
|
|
|
delim = "of";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* look for the string "part" followed by a number
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (length == 0) {
|
|
|
|
if ((iter = _FP_stristr (subject, "part")) != NULL) {
|
|
|
|
iter += 4;
|
|
|
|
|
|
|
|
while (isspace (*iter) || *iter == '.' || *iter == '-')
|
|
|
|
iter++;
|
|
|
|
|
|
|
|
while (isdigit (iter[length]))
|
|
|
|
length++;
|
|
|
|
|
|
|
|
if (length == 0) {
|
|
|
|
if (_FP_strnicmp (iter, "one", 3) == 0) length = 1;
|
|
|
|
else if (_FP_strnicmp (iter, "two", 3) == 0) length = 2;
|
|
|
|
else if (_FP_strnicmp (iter, "three", 5) == 0) length = 3;
|
|
|
|
else if (_FP_strnicmp (iter, "four", 4) == 0) length = 4;
|
|
|
|
else if (_FP_strnicmp (iter, "five", 4) == 0) length = 5;
|
|
|
|
else if (_FP_strnicmp (iter, "six", 3) == 0) length = 6;
|
|
|
|
else if (_FP_strnicmp (iter, "seven", 5) == 0) length = 7;
|
|
|
|
else if (_FP_strnicmp (iter, "eight", 5) == 0) length = 8;
|
|
|
|
else if (_FP_strnicmp (iter, "nine", 4) == 0) length = 9;
|
|
|
|
else if (_FP_strnicmp (iter, "ten", 3) == 0) length = 10;
|
|
|
|
|
|
|
|
if (length && (*whend = strchr (iter, ' '))) {
|
|
|
|
*where = iter;
|
|
|
|
return length;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
length = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*where = iter;
|
|
|
|
delim = "of";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* look for [0-9]* "of" [0-9]*
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (length == 0) {
|
|
|
|
if ((iter = _FP_strirstr (subject, "of")) != NULL) {
|
|
|
|
while (iter>subject && isspace (*(iter-1)))
|
|
|
|
iter--;
|
|
|
|
if (isdigit(*(iter-1))) {
|
|
|
|
while (iter>subject && isdigit (*(iter-1)))
|
|
|
|
iter--;
|
|
|
|
if (!isdigit (*iter) && !isalpha (*iter) && *iter != '.')
|
|
|
|
iter++;
|
|
|
|
ptr = iter;
|
|
|
|
|
|
|
|
while (isdigit (*ptr)) {
|
|
|
|
ptr++; length++;
|
|
|
|
}
|
|
|
|
*where = iter;
|
|
|
|
delim = "of";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* look for whitespace-separated (or '/'-separated) digits
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (length == 0) {
|
|
|
|
ptr = subject;
|
|
|
|
|
|
|
|
while (*ptr && length==0) {
|
|
|
|
while (*ptr && !isdigit (*ptr))
|
|
|
|
ptr++;
|
|
|
|
if (isdigit (*ptr) && (ptr==subject || *ptr==' ' || *ptr=='/')) {
|
|
|
|
while (isdigit (ptr[length]))
|
|
|
|
length++;
|
|
|
|
if (ptr[length]!='\0' && ptr[length]!=' ' && ptr[length]!='/') {
|
|
|
|
ptr += length;
|
|
|
|
length = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
iter = ptr;
|
|
|
|
bdel[0] = ptr[length];
|
|
|
|
delim = bdel;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
while (isdigit (*ptr))
|
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* look for _any_ digits -- currently disabled, because it also fell
|
|
|
|
* for "part numbers" in file names
|
|
|
|
*/
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
if (length == 0) {
|
|
|
|
count = strlen(subject) - 1;
|
|
|
|
ptr = subject;
|
|
|
|
|
|
|
|
while (count > 0) {
|
|
|
|
if (!isdigit(ptr[count])||isalpha(ptr[count+1])||ptr[count+1] == '.') {
|
|
|
|
count--;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
length = 0;
|
|
|
|
|
|
|
|
while (count >= 0 && isdigit (ptr[count])) {
|
|
|
|
count--; length++;
|
|
|
|
}
|
|
|
|
if (count>=0 && ((isalpha (ptr[count]) &&
|
|
|
|
(ptr[count] != 's' || ptr[count+1] != 't') &&
|
|
|
|
(ptr[count] != 'n' || ptr[count+1] != 'd')) ||
|
|
|
|
ptr[count] == '/' || ptr[count] == '.' ||
|
|
|
|
ptr[count] == '-' || ptr[count] == '_')) {
|
|
|
|
length = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
count++;
|
|
|
|
iter = ptr + count;
|
|
|
|
|
|
|
|
if (length > 4) {
|
|
|
|
length = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
*where = iter;
|
|
|
|
delim = "of";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* look for part numbering as string
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (length == 0) {
|
|
|
|
/*
|
|
|
|
* some people use the strangest things, including spelling mistakes :-)
|
|
|
|
*/
|
|
|
|
if ((iter = _FP_stristr (subject, "first")) != NULL) length = 1;
|
|
|
|
else if ((iter = _FP_stristr (subject, "second")) != NULL) length = 2;
|
|
|
|
else if ((iter = _FP_stristr (subject, "third")) != NULL) length = 3;
|
|
|
|
else if ((iter = _FP_stristr (subject, "forth")) != NULL) length = 4;
|
|
|
|
else if ((iter = _FP_stristr (subject, "fourth")) != NULL) length = 4;
|
|
|
|
else if ((iter = _FP_stristr (subject, "fifth")) != NULL) length = 5;
|
|
|
|
else if ((iter = _FP_stristr (subject, "sixth")) != NULL) length = 6;
|
|
|
|
else if ((iter = _FP_stristr (subject, "seventh")) != NULL) length = 7;
|
|
|
|
else if ((iter = _FP_stristr (subject, "eigth")) != NULL) length = 8;
|
|
|
|
else if ((iter = _FP_stristr (subject, "nineth")) != NULL) length = 9;
|
|
|
|
else if ((iter = _FP_stristr (subject, "ninth")) != NULL) length = 9;
|
|
|
|
else if ((iter = _FP_stristr (subject, "tenth")) != NULL) length = 10;
|
|
|
|
else iter = NULL;
|
|
|
|
|
|
|
|
if (length && iter && (*whend = strchr (iter, ' '))) {
|
|
|
|
*where = iter;
|
|
|
|
return length;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
length = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (iter == NULL || length == 0) /* should be equivalent */
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
*where = iter;
|
|
|
|
|
|
|
|
if (delim && delim[0]) {
|
|
|
|
if ((*whend=_FP_stristr (iter, delim)) != NULL && (*whend - *where) < 12) {
|
|
|
|
ptr = (*whend += strlen (delim));
|
|
|
|
|
|
|
|
while (*ptr == ' ')
|
|
|
|
ptr++;
|
|
|
|
|
|
|
|
if (isdigit (*ptr)) {
|
|
|
|
*whend = ptr;
|
|
|
|
while (isdigit (**whend))
|
|
|
|
*whend += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*whend = iter + length;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*whend = iter + length;
|
|
|
|
}
|
|
|
|
|
|
|
|
return atoi (iter);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Obtain and process some information about the data.
|
|
|
|
**/
|
|
|
|
|
|
|
|
uufile *
|
|
|
|
UUPreProcessPart (fileread *data, int *ret)
|
|
|
|
{
|
|
|
|
char *where, *whend, temp[80], *ptr, *p2;
|
|
|
|
uufile *result;
|
|
|
|
|
|
|
|
if ((result = (uufile *) malloc (sizeof (uufile))) == NULL) {
|
|
|
|
UUMessage (uucheck_id, __LINE__, UUMSG_ERROR,
|
|
|
|
uustring (S_OUT_OF_MEMORY), sizeof (uufile));
|
|
|
|
*ret = UURET_NOMEM;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
memset (result, 0, sizeof (uufile));
|
|
|
|
|
|
|
|
if (data->partno) {
|
|
|
|
where = whend = NULL;
|
|
|
|
result->partno = data->partno;
|
|
|
|
}
|
|
|
|
else if (uu_dumbness) {
|
|
|
|
result->partno = -1;
|
|
|
|
where = whend = NULL;
|
|
|
|
}
|
|
|
|
else if ((result->partno=UUGetPartNo(data->subject,&where,&whend)) == -2) {
|
|
|
|
*ret = UURET_NODATA;
|
|
|
|
UUkillfile (result);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (data->filename != NULL) {
|
|
|
|
if ((result->filename = _FP_strdup (data->filename)) == NULL) {
|
|
|
|
UUMessage (uucheck_id, __LINE__, UUMSG_ERROR,
|
|
|
|
uustring (S_OUT_OF_MEMORY),
|
|
|
|
strlen (data->filename)+1);
|
|
|
|
*ret = UURET_NOMEM;
|
|
|
|
UUkillfile (result);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
result->filename = NULL;
|
|
|
|
|
|
|
|
if (uu_dumbness <= 1)
|
|
|
|
result->subfname = UUGetFileName (data->subject, where, whend);
|
|
|
|
else
|
|
|
|
result->subfname = NULL;
|
|
|
|
|
|
|
|
result->mimeid = _FP_strdup (data->mimeid);
|
|
|
|
result->mimetype = _FP_strdup (data->mimetype);
|
|
|
|
|
|
|
|
if (result->partno == -1 &&
|
|
|
|
(data->uudet == PT_ENCODED || data->uudet == QP_ENCODED))
|
|
|
|
result->partno = 1;
|
|
|
|
|
|
|
|
if (data->flags & FL_SINGLE) {
|
|
|
|
/*
|
|
|
|
* Don't touch this part. But it should really have a filename
|
|
|
|
*/
|
|
|
|
if (result->filename == NULL) {
|
|
|
|
sprintf (temp, "%s.%03d", nofname, ++nofnum);
|
|
|
|
result->filename = _FP_strdup (temp);
|
|
|
|
}
|
|
|
|
if (result->subfname == NULL)
|
|
|
|
result->subfname = _FP_strdup (result->filename);
|
|
|
|
|
|
|
|
if (result->filename == NULL ||
|
|
|
|
result->subfname == NULL) {
|
|
|
|
UUMessage (uucheck_id, __LINE__, UUMSG_ERROR,
|
|
|
|
uustring (S_OUT_OF_MEMORY),
|
|
|
|
(result->filename==NULL)?
|
|
|
|
(strlen(temp)+1):(strlen(result->filename)+1));
|
|
|
|
*ret = UURET_NOMEM;
|
|
|
|
UUkillfile(result);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (result->partno == -1)
|
|
|
|
result->partno = 1;
|
|
|
|
}
|
|
|
|
else if (result->subfname == NULL && data->uudet &&
|
|
|
|
(data->begin || result->partno == 1 ||
|
|
|
|
(!uu_dumbness && result->partno == -1 &&
|
|
|
|
(data->subject != NULL || result->filename != NULL)))) {
|
|
|
|
/*
|
|
|
|
* If it's the first part of something and has some valid data, but
|
|
|
|
* no subject or anything, initialize lastvalid
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* in this case, it really _should_ have a filename somewhere
|
|
|
|
*/
|
|
|
|
if (result->filename != NULL)
|
|
|
|
result->subfname = _FP_strdup (result->filename);
|
|
|
|
else { /* if not, escape to UNKNOWN. We need to fill subfname */
|
|
|
|
sprintf (temp, "%s.%03d", nofname, ++nofnum);
|
|
|
|
result->subfname = _FP_strdup (temp);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* in case the strdup failed
|
|
|
|
*/
|
|
|
|
if (result->subfname == NULL) {
|
|
|
|
UUMessage (uucheck_id, __LINE__, UUMSG_ERROR,
|
|
|
|
uustring (S_OUT_OF_MEMORY),
|
|
|
|
(result->filename)?
|
|
|
|
(strlen(result->filename)+1):(strlen(temp)+1));
|
|
|
|
*ret = UURET_NOMEM;
|
|
|
|
UUkillfile (result);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* if it's also got an 'end', or is the last part in a MIME-Mail,
|
|
|
|
* then don't set lastvalid
|
|
|
|
*/
|
|
|
|
if (!data->end && (!data->partno || data->partno != data->maxpno)) {
|
|
|
|
/*
|
|
|
|
* initialize lastvalid
|
|
|
|
*/
|
|
|
|
lastvalid = 1;
|
|
|
|
lastenc = data->uudet;
|
|
|
|
lastpart = result->partno = 1;
|
|
|
|
_FP_strncpy (uucheck_lastname, result->subfname, 256);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
result->partno = 1;
|
|
|
|
}
|
|
|
|
else if (result->subfname == NULL && data->uudet && data->mimeid) {
|
|
|
|
/*
|
|
|
|
* if it's got a file name, use it. Else use the mime-id for identifying
|
|
|
|
* this part, and hope there's no other files encoded in the same message
|
|
|
|
* under the same id.
|
|
|
|
*/
|
|
|
|
if (result->filename)
|
|
|
|
result->subfname = _FP_strdup (result->filename);
|
|
|
|
else
|
|
|
|
result->subfname = _FP_strdup (result->mimeid);
|
|
|
|
}
|
|
|
|
else if (result->subfname == NULL && data->uudet) {
|
|
|
|
/*
|
|
|
|
* ff we have lastvalid, use it. Make an exception for
|
|
|
|
* Base64-encoded files.
|
|
|
|
*/
|
|
|
|
if (data->uudet == B64ENCODED) {
|
|
|
|
/*
|
|
|
|
* Assume it's the first part. I wonder why it's got no part number?
|
|
|
|
*/
|
|
|
|
if (result->filename != NULL)
|
|
|
|
result->subfname = _FP_strdup (result->filename);
|
|
|
|
else { /* if not, escape to UNKNOWN. We need to fill subfname */
|
|
|
|
sprintf (temp, "%s.%03d", nofname, ++nofnum);
|
|
|
|
result->subfname = _FP_strdup (temp);
|
|
|
|
}
|
|
|
|
if (result->subfname == NULL) {
|
|
|
|
UUMessage (uucheck_id, __LINE__, UUMSG_ERROR,
|
|
|
|
uustring (S_OUT_OF_MEMORY),
|
|
|
|
(result->filename)?
|
|
|
|
(strlen(result->filename)+1):(strlen(temp)+1));
|
|
|
|
*ret = UURET_NOMEM;
|
|
|
|
UUkillfile (result);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
lastvalid = 0;
|
|
|
|
}
|
2001-11-01 17:20:18 +00:00
|
|
|
else if (lastvalid && data->uudet == lastenc && result->partno <= 0) {
|
2000-02-25 10:15:17 +00:00
|
|
|
result->subfname = _FP_strdup (uucheck_lastname);
|
|
|
|
result->partno = ++lastpart;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* if it's the last part, invalidate lastvalid
|
|
|
|
*/
|
|
|
|
if (data->end || (data->partno && data->partno == data->maxpno))
|
|
|
|
lastvalid = 0;
|
|
|
|
}
|
2001-11-01 17:20:18 +00:00
|
|
|
else if (data->partno != -1 && result->filename) {
|
|
|
|
result->subfname = _FP_strdup (result->filename);
|
|
|
|
}
|
|
|
|
else {
|
2000-02-25 10:15:17 +00:00
|
|
|
/*
|
|
|
|
* it's got no info, it's got no begin, and we don't know anything
|
|
|
|
* about this part. Let's forget all about it.
|
|
|
|
*/
|
|
|
|
*ret = UURET_NODATA;
|
|
|
|
UUkillfile (result);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (result->subfname == NULL && result->partno == -1) {
|
|
|
|
/*
|
|
|
|
* This, too, is a part without any useful information that we
|
|
|
|
* should forget about.
|
|
|
|
*/
|
|
|
|
*ret = UURET_NODATA;
|
|
|
|
UUkillfile (result);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else if (result->subfname == NULL) {
|
|
|
|
/*
|
|
|
|
* This is a part without useful subject name, a valid part number
|
|
|
|
* but no encoded data. It *could* be the zeroeth part of something,
|
|
|
|
* but we don't care here. Just forget it.
|
|
|
|
*/
|
|
|
|
*ret = UURET_NODATA;
|
|
|
|
UUkillfile (result);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* now, handle some cases where we have a useful subject but no
|
|
|
|
* useful part number
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (result->partno == -1 && data->begin) {
|
|
|
|
/*
|
|
|
|
* hmm, this is reason enough to initialize lastvalid, at least
|
|
|
|
* if we have no end
|
|
|
|
*/
|
|
|
|
if (!data->end) {
|
|
|
|
_FP_strncpy (uucheck_lastname, result->subfname, 256);
|
|
|
|
result->partno = lastpart = 1;
|
|
|
|
lastenc = data->uudet;
|
|
|
|
lastvalid = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
result->partno = 1;
|
|
|
|
}
|
|
|
|
else if (result->partno == -1 && data->uudet) {
|
|
|
|
if (lastvalid && _FP_stricmp (uucheck_lastname, result->subfname) == 0) {
|
|
|
|
/*
|
|
|
|
* if the subject filename is the same as last time, use part no
|
|
|
|
* of lastvalid. If at end, invalidate lastvalid
|
|
|
|
*/
|
|
|
|
result->partno = ++lastpart;
|
|
|
|
|
|
|
|
if (data->end)
|
|
|
|
lastvalid = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/*
|
|
|
|
* data but no part no. It's something UUInsertPartToList() should
|
|
|
|
* handle
|
|
|
|
*/
|
|
|
|
goto skipcheck;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (result->partno == -1) {
|
|
|
|
/*
|
|
|
|
* it's got no data, so why should we need this one anyway?
|
|
|
|
*/
|
|
|
|
*ret = UURET_NODATA;
|
|
|
|
UUkillfile (result);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* at this point, the part should have a valid subfname and a valid
|
|
|
|
* part number. If it doesn't, then fail.
|
|
|
|
*/
|
|
|
|
if (result->subfname == NULL || result->partno == -1) {
|
|
|
|
*ret = UURET_NODATA;
|
|
|
|
UUkillfile (result);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
skipcheck:
|
|
|
|
|
|
|
|
if (result->filename) {
|
|
|
|
if (*(ptr = _FP_cutdir (result->filename))) {
|
|
|
|
p2 = _FP_strdup (ptr);
|
|
|
|
_FP_free (result->filename);
|
|
|
|
result->filename = p2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result->data = data;
|
|
|
|
result->NEXT = NULL;
|
|
|
|
|
|
|
|
*ret = UURET_OK;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Insert one part of a file into the global list
|
|
|
|
**/
|
|
|
|
|
|
|
|
int
|
|
|
|
UUInsertPartToList (uufile *data)
|
|
|
|
{
|
|
|
|
uulist *iter = UUGlobalFileList, *unew;
|
|
|
|
uufile *fiter, *last;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Part belongs together, if
|
|
|
|
* (a) The file name received from the subject lines match _or_
|
|
|
|
* the MIME-IDs match,
|
|
|
|
* (b) Not both parts have a begin line
|
|
|
|
* (c) Not both parts have an end line
|
|
|
|
* (d) Both parts don't have different MIME-IDs
|
|
|
|
* (e) Both parts don't encode different files
|
|
|
|
* (f) The other part wants to stay alone (FL_SINGLE)
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* check if this part wants to be left alone. If so, don't bother
|
|
|
|
* to do all the checks
|
|
|
|
*/
|
|
|
|
|
|
|
|
while (iter) {
|
|
|
|
if (data->data->flags & FL_SINGLE) {
|
|
|
|
/* this space intentionally left blank */
|
|
|
|
}
|
|
|
|
else if ((_FP_stricmp (data->subfname, iter->subfname) == 0 ||
|
|
|
|
(data->mimeid && iter->mimeid &&
|
|
|
|
strcmp (data->mimeid, iter->mimeid) == 0)) &&
|
|
|
|
!(iter->begin && data->data->begin) &&
|
|
|
|
!(iter->end && data->data->end) &&
|
|
|
|
!(data->mimeid && iter->mimeid &&
|
|
|
|
strcmp (data->mimeid, iter->mimeid) != 0) &&
|
|
|
|
!(data->filename && iter->filename &&
|
|
|
|
strcmp (data->filename, iter->filename) != 0) &&
|
|
|
|
!(iter->flags & FL_SINGLE)) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* if we already have this part, don't try to insert it
|
|
|
|
*/
|
|
|
|
|
|
|
|
for (fiter=iter->thisfile;
|
|
|
|
fiter && (data->partno>fiter->partno) && !fiter->data->end;
|
|
|
|
fiter=fiter->NEXT)
|
|
|
|
/* empty loop */ ;
|
|
|
|
if (fiter &&
|
|
|
|
(data->partno==fiter->partno ||
|
|
|
|
(data->partno > fiter->partno && fiter->data->end)))
|
|
|
|
goto goahead;
|
|
|
|
|
|
|
|
if (iter->filename == NULL && data->filename != NULL) {
|
|
|
|
if ((iter->filename = _FP_strdup (data->filename)) == NULL)
|
|
|
|
return UURET_NOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* special case when we might have tagged a part as Base64 when the
|
|
|
|
* file was really XX
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (data->data->uudet == B64ENCODED &&
|
|
|
|
iter->uudet == XX_ENCODED && iter->begin) {
|
|
|
|
data->data->uudet = XX_ENCODED;
|
|
|
|
}
|
|
|
|
else if (data->data->uudet == XX_ENCODED && data->data->begin &&
|
|
|
|
iter->uudet == B64ENCODED) {
|
|
|
|
iter->uudet = XX_ENCODED;
|
|
|
|
|
|
|
|
fiter = iter->thisfile;
|
|
|
|
while (fiter) {
|
|
|
|
fiter->data->uudet = XX_ENCODED;
|
|
|
|
fiter = fiter->NEXT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If this is from a Message/Partial, we believe only the
|
|
|
|
* iter->uudet from the first part
|
|
|
|
*/
|
|
|
|
if (data->data->flags & FL_PARTIAL) {
|
|
|
|
if (data->partno == 1) {
|
|
|
|
iter->uudet = data->data->uudet;
|
|
|
|
iter->flags = data->data->flags;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (data->data->uudet) iter->uudet = data->data->uudet;
|
|
|
|
if (data->data->flags) iter->flags = data->data->flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (iter->mode == 0 && data->data->mode != 0)
|
|
|
|
iter->mode = data->data->mode;
|
|
|
|
if (data->data->begin) iter->begin = (data->partno)?data->partno:1;
|
|
|
|
if (data->data->end) iter->end = (data->partno)?data->partno:1;
|
|
|
|
|
|
|
|
if (data->mimetype) {
|
|
|
|
_FP_free (iter->mimetype);
|
|
|
|
iter->mimetype = _FP_strdup (data->mimetype);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* insert part at the beginning
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (data->partno != -1 && data->partno < iter->thisfile->partno) {
|
|
|
|
iter->state = UUFILE_READ;
|
|
|
|
data->NEXT = iter->thisfile;
|
|
|
|
iter->thisfile = data;
|
|
|
|
return UURET_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* insert part somewhere else
|
|
|
|
*/
|
|
|
|
|
|
|
|
iter->state = UUFILE_READ; /* prepare for re-checking */
|
|
|
|
fiter = iter->thisfile;
|
|
|
|
last = NULL;
|
|
|
|
|
|
|
|
while (fiter) {
|
|
|
|
/*
|
|
|
|
* if we find the same part no again, check which one looks better
|
|
|
|
*/
|
|
|
|
if (data->partno == fiter->partno) {
|
|
|
|
if (fiter->data->subject == NULL)
|
|
|
|
return UURET_NODATA;
|
|
|
|
else if (_FP_stristr (fiter->data->subject, "repost") != NULL &&
|
|
|
|
_FP_stristr (data->data->subject, "repost") == NULL)
|
|
|
|
return UURET_NODATA;
|
|
|
|
else if (fiter->data->uudet && !data->data->uudet)
|
|
|
|
return UURET_NODATA;
|
|
|
|
else {
|
|
|
|
/*
|
|
|
|
* replace
|
|
|
|
*/
|
|
|
|
data->NEXT = fiter->NEXT;
|
|
|
|
fiter->NEXT = NULL;
|
|
|
|
UUkillfile (fiter);
|
|
|
|
|
|
|
|
if (last == NULL)
|
|
|
|
iter->thisfile = data;
|
|
|
|
else
|
|
|
|
last->NEXT = data;
|
|
|
|
|
|
|
|
return UURET_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* if at the end of the part list, add it
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (fiter->NEXT == NULL ||
|
|
|
|
(data->partno != -1 && data->partno < fiter->NEXT->partno)) {
|
|
|
|
data->NEXT = fiter->NEXT;
|
|
|
|
fiter->NEXT = data;
|
|
|
|
|
|
|
|
if (data->partno == -1)
|
|
|
|
data->partno = fiter->partno + 1;
|
|
|
|
|
|
|
|
return UURET_OK;
|
|
|
|
}
|
|
|
|
last = fiter;
|
|
|
|
fiter = fiter->NEXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
return UURET_OK; /* Shouldn't get here */
|
|
|
|
}
|
|
|
|
goahead:
|
|
|
|
/*
|
|
|
|
* we need iter below
|
|
|
|
*/
|
|
|
|
if (iter->NEXT == NULL)
|
|
|
|
break;
|
|
|
|
|
|
|
|
iter = iter->NEXT;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* handle new entry
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (data->partno == -1) {
|
|
|
|
/*
|
|
|
|
* if it's got no part no, and it's MIME mail, then assume this is
|
|
|
|
* part no. 1. If it's not MIME, then we can't handle it; if it
|
|
|
|
* had a 'begin', it'd have got a part number assigned by
|
|
|
|
* UUPreProcessPart().
|
|
|
|
*/
|
|
|
|
if (data->data->uudet == B64ENCODED || data->data->uudet == BH_ENCODED)
|
|
|
|
data->partno = 1;
|
|
|
|
else
|
|
|
|
return UURET_NODATA;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((unew = (uulist *) malloc (sizeof (uulist))) == NULL) {
|
|
|
|
return UURET_NOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((unew->subfname = _FP_strdup (data->subfname)) == NULL) {
|
|
|
|
_FP_free (unew);
|
|
|
|
return UURET_NOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (data->filename != NULL) {
|
|
|
|
if ((unew->filename = _FP_strdup (data->filename)) == NULL) {
|
|
|
|
_FP_free (unew->subfname);
|
|
|
|
_FP_free (unew);
|
|
|
|
return UURET_NOMEM;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
unew->filename = NULL;
|
|
|
|
|
|
|
|
if (data->mimeid != NULL) {
|
|
|
|
if ((unew->mimeid = _FP_strdup (data->mimeid)) == NULL) {
|
|
|
|
_FP_free (unew->subfname);
|
|
|
|
_FP_free (unew->filename);
|
|
|
|
_FP_free (unew);
|
|
|
|
return UURET_NOMEM;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
unew->mimeid = NULL;
|
|
|
|
|
|
|
|
if (data->mimetype != NULL) {
|
|
|
|
if ((unew->mimetype = _FP_strdup (data->mimetype)) == NULL) {
|
|
|
|
_FP_free (unew->mimeid);
|
|
|
|
_FP_free (unew->subfname);
|
|
|
|
_FP_free (unew->filename);
|
|
|
|
_FP_free (unew);
|
|
|
|
return UURET_NOMEM;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
unew->mimetype = NULL;
|
|
|
|
|
|
|
|
unew->state = UUFILE_READ;
|
|
|
|
unew->binfile = NULL;
|
|
|
|
unew->thisfile = data;
|
|
|
|
unew->mode = data->data->mode;
|
|
|
|
unew->uudet = data->data->uudet;
|
|
|
|
unew->flags = data->data->flags;
|
|
|
|
unew->begin = (data->data->begin) ? ((data->partno)?data->partno:1) : 0;
|
|
|
|
unew->end = (data->data->end) ? ((data->partno)?data->partno:1) : 0;
|
|
|
|
unew->misparts = NULL;
|
|
|
|
unew->haveparts = NULL;
|
|
|
|
unew->NEXT = NULL;
|
|
|
|
|
|
|
|
if (iter == NULL)
|
|
|
|
UUGlobalFileList = unew;
|
|
|
|
else
|
|
|
|
iter->NEXT = unew;
|
|
|
|
|
|
|
|
return UURET_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* At this point, all files are read in and stored in the
|
|
|
|
* "UUGlobalFileList". Do some checking. All parts there?
|
|
|
|
**/
|
|
|
|
|
|
|
|
uulist *
|
|
|
|
UUCheckGlobalList (void)
|
|
|
|
{
|
|
|
|
int misparts[MAXPLIST], haveparts[MAXPLIST];
|
|
|
|
int miscount, havecount, count, flag, part;
|
|
|
|
uulist *liter=UUGlobalFileList, *prev;
|
|
|
|
uufile *fiter;
|
|
|
|
long thesize;
|
|
|
|
|
|
|
|
while (liter) {
|
|
|
|
miscount = 0;
|
|
|
|
thesize = 0;
|
|
|
|
|
|
|
|
if (liter->state & UUFILE_OK) {
|
|
|
|
liter = liter->NEXT;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if ((liter->uudet == QP_ENCODED ||
|
|
|
|
liter->uudet == PT_ENCODED) &&
|
|
|
|
(liter->flags & FL_SINGLE)) {
|
|
|
|
if ((liter->flags&FL_PROPER)==0)
|
|
|
|
liter->size = -1;
|
|
|
|
else
|
|
|
|
liter->size = liter->thisfile->data->length;
|
|
|
|
|
|
|
|
liter->state = UUFILE_OK;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if ((fiter = liter->thisfile) == NULL) {
|
|
|
|
liter->state = UUFILE_NODATA;
|
|
|
|
liter = liter->NEXT;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Re-Check this file
|
|
|
|
*/
|
|
|
|
|
|
|
|
flag = 0;
|
|
|
|
miscount = 0;
|
|
|
|
havecount = 0;
|
|
|
|
thesize = 0;
|
|
|
|
liter->state = UUFILE_READ;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* search encoded data
|
|
|
|
*/
|
|
|
|
|
|
|
|
while (fiter && !fiter->data->uudet) {
|
|
|
|
if (havecount<MAXPLIST) {
|
|
|
|
haveparts[havecount++] = fiter->partno;
|
|
|
|
}
|
|
|
|
fiter = fiter->NEXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fiter == NULL) {
|
|
|
|
liter->state = UUFILE_NODATA;
|
|
|
|
liter = liter->NEXT;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (havecount<MAXPLIST) {
|
|
|
|
haveparts[havecount++] = fiter->partno;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((part = fiter->partno) > 1) {
|
|
|
|
if (!fiter->data->begin) {
|
|
|
|
for (count=1; count < part && miscount < MAXPLIST; count++)
|
|
|
|
misparts[miscount++] = count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* don't care if so many parts are missing
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (miscount >= MAXPLIST) {
|
|
|
|
liter->state = UUFILE_MISPART;
|
|
|
|
liter = liter->NEXT;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (liter->uudet == B64ENCODED ||
|
|
|
|
liter->uudet == QP_ENCODED ||
|
|
|
|
liter->uudet == PT_ENCODED)
|
|
|
|
flag |= 3; /* Don't need begin or end with Base64 or plain text*/
|
|
|
|
|
|
|
|
if (fiter->data->begin) flag |= 1;
|
|
|
|
if (fiter->data->end) flag |= 2;
|
|
|
|
if (fiter->data->uudet) flag |= 4;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* guess size of part
|
|
|
|
*/
|
|
|
|
|
|
|
|
switch (fiter->data->uudet) {
|
|
|
|
case UU_ENCODED:
|
|
|
|
case XX_ENCODED:
|
|
|
|
thesize += 3*fiter->data->length/4;
|
|
|
|
thesize -= 3*fiter->data->length/124; /* substract 2 of 62 chars */
|
|
|
|
break;
|
|
|
|
case B64ENCODED:
|
|
|
|
thesize += 3*fiter->data->length/4;
|
|
|
|
thesize -= fiter->data->length/52; /* substract 2 of 78 chars */
|
|
|
|
break;
|
|
|
|
case QP_ENCODED:
|
|
|
|
case PT_ENCODED:
|
|
|
|
thesize += fiter->data->length;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
fiter = fiter->NEXT;
|
|
|
|
|
|
|
|
while (fiter != NULL) {
|
|
|
|
for (count=part+1; count<fiter->partno && miscount<MAXPLIST; count++)
|
|
|
|
misparts[miscount++] = count;
|
|
|
|
|
|
|
|
part = fiter->partno;
|
|
|
|
|
|
|
|
if (havecount<MAXPLIST)
|
|
|
|
haveparts[havecount++]=part;
|
|
|
|
|
|
|
|
if (fiter->data->begin) flag |= 1;
|
|
|
|
if (fiter->data->end) flag |= 2;
|
|
|
|
if (fiter->data->uudet) flag |= 4;
|
|
|
|
|
|
|
|
switch (fiter->data->uudet) {
|
|
|
|
case UU_ENCODED:
|
|
|
|
case XX_ENCODED:
|
|
|
|
thesize += 3*fiter->data->length/4;
|
|
|
|
thesize -= 3*fiter->data->length/124; /* substract 2 of 62 chars */
|
|
|
|
break;
|
|
|
|
case B64ENCODED:
|
|
|
|
thesize += 3*fiter->data->length/4;
|
|
|
|
thesize -= fiter->data->length/52; /* substract 2 of 78 chars */
|
|
|
|
break;
|
|
|
|
case QP_ENCODED:
|
|
|
|
case PT_ENCODED:
|
|
|
|
thesize += fiter->data->length;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fiter->data->end)
|
|
|
|
break;
|
|
|
|
|
|
|
|
fiter = fiter->NEXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* if in fast mode, we don't notice an 'end'. So if its uu or xx
|
|
|
|
* encoded, there's a begin line and encoded data, assume it's
|
|
|
|
* there.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (uu_fast_scanning && (flag & 0x01) && (flag & 0x04) &&
|
|
|
|
(liter->uudet == UU_ENCODED || liter->uudet == XX_ENCODED))
|
|
|
|
flag |= 2;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set the parts we have and/or missing
|
|
|
|
*/
|
|
|
|
|
|
|
|
_FP_free (liter->haveparts);
|
|
|
|
_FP_free (liter->misparts);
|
|
|
|
|
|
|
|
liter->haveparts = NULL;
|
|
|
|
liter->misparts = NULL;
|
|
|
|
|
|
|
|
if (havecount) {
|
|
|
|
if ((liter->haveparts=(int*)malloc((havecount+1)*sizeof(int)))!=NULL) {
|
|
|
|
memcpy (liter->haveparts, haveparts, havecount*sizeof(int));
|
|
|
|
liter->haveparts[havecount] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (miscount) {
|
|
|
|
if ((liter->misparts=(int*)malloc((miscount+1)*sizeof(int)))!=NULL) {
|
|
|
|
memcpy (liter->misparts, misparts, miscount*sizeof(int));
|
|
|
|
liter->misparts[miscount] = 0;
|
|
|
|
}
|
|
|
|
liter->state |= UUFILE_MISPART;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Finalize checking
|
|
|
|
*/
|
|
|
|
|
|
|
|
if ((flag & 4) == 0) liter->state |= UUFILE_NODATA;
|
|
|
|
if ((flag & 1) == 0) liter->state |= UUFILE_NOBEGIN;
|
|
|
|
if ((flag & 2) == 0) liter->state |= UUFILE_NOEND;
|
|
|
|
|
|
|
|
if ((flag & 7) == 7 && miscount==0) {
|
|
|
|
liter->state = UUFILE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((uu_fast_scanning && (liter->flags&FL_PROPER)==0) || thesize<=0)
|
|
|
|
liter->size = -1;
|
|
|
|
else
|
|
|
|
liter->size = thesize;
|
|
|
|
|
|
|
|
if (liter->state==UUFILE_OK &&
|
|
|
|
(liter->filename==NULL || liter->filename[0]=='\0')) {
|
|
|
|
/*
|
|
|
|
* Emergency backup if the file does not have a filename
|
|
|
|
*/
|
|
|
|
_FP_free (liter->filename);
|
|
|
|
if (liter->subfname && liter->subfname[0] &&
|
|
|
|
_FP_strpbrk (liter->subfname, "()[];: ") == NULL)
|
|
|
|
liter->filename = _FP_strdup (liter->subfname);
|
|
|
|
else {
|
|
|
|
sprintf (uucheck_tempname, "%s.%03d", nofname, ++nofnum);
|
|
|
|
liter->filename = _FP_strdup (uucheck_tempname);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
liter = liter->NEXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Sets back (PREV) links
|
|
|
|
*/
|
|
|
|
|
|
|
|
liter = UUGlobalFileList;
|
|
|
|
prev = NULL;
|
|
|
|
|
|
|
|
while (liter) {
|
|
|
|
liter->PREV = prev;
|
|
|
|
prev = liter;
|
|
|
|
liter = liter->NEXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
return UUGlobalFileList;
|
|
|
|
}
|
|
|
|
|