home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Professional
/
OS2PRO194.ISO
/
os2
/
packer
/
uugrab
/
uugrab.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-07
|
24KB
|
967 lines
/* uugrab.c (c) 1992 by Harald Boegeholz */
/* contains parts of the program uucat which was placed in the public
domain by d84sp@efd.lth.se (Stefan Parmark) */
/* customize these for use with different shells */
#define SHELL_COMMAND_ECHO "echo"
#ifdef OS2
#define SHELL_COMMAND_COMMENT "REM"
#else
#define SHELL_COMMAND_COMMENT "#"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#ifdef OS2
#define INCL_DOSFILEMGR
#define INCL_DOSERRORS
#include <os2.h>
#endif
#if !defined(OS2)
#define _popen popen
#define _pclose pclose
#endif
#define BUFFER_SIZE 1000
#define MAX_LINE_LEN 1042
typedef int boolean;
#define TRUE 1
#define FALSE 0
#define UFIRST 'M'
#define UQUOTE '`'
#define LENGTH 150
struct _part_list
{
char *filename;
char *msgid;
int partno;
struct _part_list *next;
};
static struct _subj_list
{
char *subject;
int nparts;
struct _part_list *partlist;
struct _subj_list *next;
} *subject_list=NULL;
static struct _msgid_list
{
char *msgid;
boolean visited;
struct _msgid_list *left;
struct _msgid_list *right;
struct _msgid_list *next;
} *old_msgid_list=NULL;
static struct _msgid_list *dummy_next;
static struct _msgid_list **last_msgid_next_ptr=&dummy_next;
#if defined(OS2)
static char history_file_name[]="uugrab.rc";
#else
static char history_file_name[]=".uugrabrc";
#endif
static void error(char *, ...);
int main(int, char *[]);
static void read_history(void);
static void save_history(void);
static boolean already_processed(char *msgid, boolean add, boolean setvisited);
static void read_subjects(char *filespec);
static void find_subject(char *filename);
static void parse_subject(char *filename, char *subject, char *msgid);
static void store_part(char *filename, char *subject, char *msgid,
int partno, int nparts);
static void add_article(struct _part_list **partlist, char *filename,
char *msgid, int partno);
static void output_results(void);
static void print_malformed(struct _subj_list *p);
static void begin_uucat(void);
static void end_uucat(void);
static void uucat_file(char *filename);
static int is_begin_line(char *s);
static boolean option_decode_all=FALSE;
static boolean option_dont_execute=FALSE;
static boolean option_save_descriptions=FALSE;
static boolean option_verbose=FALSE;
static int ignore_fields=0;
static char *command=NULL;
static FILE *uudecode;
static FILE *description_file;
static char *description_file_name;
static boolean echo_on, started, just_finished;
static int line_length, lines_to_go;
static boolean echo_description;
static char uu_name[LENGTH];
#ifdef OS2
static void check_error(int err, int line, char *file);
#define chk(err) check_error(err, __LINE__, __FILE__)
static void check_error(int err, int line, char *file)
{
if (err==0)
return;
error("Unexpected OS/2 error occured: code %d. Sourcefile %s (line %d)\n",
err, file, line);
}
#endif
#if defined(NOSTRICMP)
/* stricmp.c (emx/gcc) -- Copyright (c) 1990-1992 by Eberhard Mattes */
int stricmp (const char *string1, const char *string2)
{
int d;
for (;;)
{
d = tolower((unsigned char)*string1) -
tolower((unsigned char)*string2);
if (d != 0 || *string1 == 0 || *string2 == 0)
return (d);
++string1; ++string2;
}
}
/* strnicmp.c (emx/gcc) -- Copyright (c) 1990-1992 by Eberhard Mattes */
int strnicmp (const char *string1, const char *string2, size_t count)
{
int d;
while (count != 0)
{
d = tolower((unsigned char)*string1) -
tolower((unsigned char)*string2);
if (d != 0 || *string1 == 0 || *string2 == 0)
return (d);
++string1; ++string2;
--count;
}
return (0);
}
#endif
static void error(char *fmt, ...)
{
va_list arg_ptr;
va_start(arg_ptr,fmt);
vprintf(fmt,arg_ptr);
va_end(arg_ptr);
exit(2);
}
static void read_history(void)
{
FILE *fp;
char line[MAX_LINE_LEN];
if (NULL==(fp=fopen(history_file_name, "r")))
{
fprintf(stderr, "*** Warning: History file '%s' not found\n", history_file_name);
return;
}
while (fgets(line, MAX_LINE_LEN, fp))
{
if (already_processed(line, TRUE, FALSE))
error("*** History file corrupt. Aborting.\n");
}
if (ferror(fp))
error("*** error reading history file\n");
fclose(fp);
} /* read_history */
static boolean already_processed(char *msgid, boolean add, boolean setvisited)
{
struct _msgid_list **p=&old_msgid_list;
int d;
while (*p)
{
d=strcmp(msgid, (*p)->msgid);
if (d==0)
{
(*p)->visited=setvisited;
return TRUE;
}
else if (d<0)
p=&(*p)->left;
else
p=&(*p)->right;
}
if (add)
{
if (NULL==(*p=malloc(sizeof (struct _msgid_list))))
error("*** Out of memory (alloc msgid_list)\n");
if (NULL==((*p)->msgid=malloc(strlen(msgid)+1)))
error("*** Out of memory (alloc msgid)\n");
strcpy((*p)->msgid, msgid);
(*p)->visited=setvisited;
(*p)->left = (*p)->right = (*p)->next = NULL;
*last_msgid_next_ptr=*p;
last_msgid_next_ptr=&(*p)->next;
}
return FALSE;
} /* already_processed */
static void save_history(void)
{
FILE *fp;
struct _msgid_list *p=old_msgid_list;
if (NULL==(fp=fopen(history_file_name, "w")))
{
fprintf(stderr, "*** Warning: cannot open history file '%s' for writing\n", history_file_name);
return;
}
while (p)
{
if (p->visited)
fputs(p->msgid, fp);
p=p->next;
}
if (ferror(fp))
error("*** error writing history file.\n");
fclose(fp);
} /* save_history */
static void read_subjects(char *filespec)
{
#ifdef OS2
USHORT res;
HDIR hdir=HDIR_SYSTEM;
FILEFINDBUF *buffer;
USHORT usCount=1;
int i;
char pathspec[_MAX_FNAME], foundfile[_MAX_FNAME];
if (NULL == (buffer= (FILEFINDBUF *) malloc(BUFFER_SIZE)))
error("*** Out of memory (alloc filefindbuf)\n");
for (i=strlen(filespec); --i>=0 && filespec[i]!='\\' && filespec[i]!=':';);
strcpy(pathspec, filespec);
pathspec[i+1]='\0';
res=DosFindFirst(filespec, &hdir, FILE_NORMAL, buffer, BUFFER_SIZE,
&usCount, 0L);
while (res==0 && usCount>0)
{
find_subject(strcat(strcpy(foundfile, pathspec), &buffer->achName[0]));
/* usCount=1; anyway */
res=DosFindNext(hdir, buffer, BUFFER_SIZE, &usCount);
}
if (res != ERROR_NO_MORE_FILES)
chk(res);
DosFindClose(hdir);
free(buffer);
#else
find_subject(filespec);
#endif
} /* read_subjects */
static void find_subject(char *filename)
{
FILE *article;
char line[MAX_LINE_LEN];
char subject[MAX_LINE_LEN];
char msgid[MAX_LINE_LEN];
boolean found_subject=FALSE, found_msgid=FALSE;
if (NULL==(article=fopen(filename, "r")))
{
fprintf(stderr, "Warning: can't open '%s'\n", filename);
return;
}
while (!feof(article) && !ferror(article) && (!found_subject || !found_msgid))
{
fgets(line, MAX_LINE_LEN, article);
if (strlen(line) <= 1) /* empty line signalizes end of headers */
break;
if (!found_subject && strnicmp(line, "Subject: ", 9) == 0)
{
strcpy(subject, &line[9]);
found_subject=TRUE;
}
if (!found_msgid && strnicmp(line, "Message-ID: ", 12) == 0)
{
strcpy(msgid, &line[12]);
found_msgid=TRUE;
}
}
if (!found_subject)
fprintf(stderr, "Article '%s' has no Subject\n", filename);
else if (!found_msgid)
fprintf(stderr, "Article '%s' has no Message-ID\n", filename);
else if (already_processed(msgid, FALSE, TRUE))
{
if (option_verbose)
fprintf(stderr, "Skipping old article '%s'...\n", filename);
}
else
{
if (subject[strlen(subject)-1] == '\n')
subject[strlen(subject)-1] = '\0'; /* remove trailing linefeed */
parse_subject(filename, subject, msgid);
}
fclose(article);
} /* find_subject */
static void parse_subject(char *filename, char *subject, char *msgid)
{
char *beg_partno, *beg_nparts, *end_nparts;
char *p;
int i;
int partno, nparts;
char *new_subject;
#ifdef DEBUG
fprintf(stderr, " Article '%s' has subject '%s'.\n", filename, subject);
#endif
for (i=0; i<ignore_fields; ++i)
{
while (*subject && *subject != ' ' && *subject != '\t') ++subject;
while (*subject && (*subject==' ' || *subject == '\t')) ++subject;
if (! *subject)
{
fprintf(stderr, "Subject of article '%s' has too few fields\n", filename);
already_processed(msgid, TRUE, TRUE); /* don't parse this article again */
return;
}
}
p=&subject[strlen(subject)-1];
/* no spaghetti, but a finite state machine :-) looking for
<digits> [<whitespace>] ( "of" | "/" ) [<whitespace>] <digits>
working backwards from the end of the subject */
state_nothing:
if (p==subject) goto not_found;
while (!isdigit(*p) && p != subject) --p;
if (p==subject) goto not_found;
end_nparts=p;
/* found a digit, looking for number of parts */
while (isdigit(*p) && p != subject) --p;
if (p==subject) goto not_found;
beg_nparts=p+1;
/* found number of parts, skip whitespace */
while ((*p == ' ' || *p == '\t') && p != subject) --p;
if (p==subject) goto not_found;
if (*p != '/')
{
if ((*p!='f' && *p!='F' || *(p-1)!='o' && *(p-1)!='O'))
{
p=end_nparts - 1;
goto state_nothing;
}
else
if (--p == subject) goto not_found;
}
if (--p == subject) goto not_found;
/* found "of" or "/", skip whitespace */
while ((*p == ' ' || *p == '\t') && p != subject) --p;
if (!isdigit(*p))
{
p=end_nparts - 1;
goto state_nothing;
}
while (p!=subject && isdigit(*(p-1))) --p;
beg_partno=p;
partno=atoi(beg_partno);
nparts=atoi(beg_nparts);
if (NULL == (new_subject=malloc(strlen(subject)+1)))
error("*** Out of memory (malloc new_subject)\n");
strcpy(new_subject, subject);
strcpy(new_subject+(beg_partno-subject), end_nparts+1);
store_part(filename, new_subject, msgid, partno, nparts);
free(new_subject);
return;
not_found:
if (option_decode_all)
store_part(filename, subject, msgid, 1, 1);
else
{
fprintf(stderr, " Article '%s' has no part numbers: '%s'\n", filename, subject);
already_processed(msgid, TRUE, TRUE); /* don't parse this article again */
}
return;
} /* parse_subject */
static void store_part(char *filename, char *subject, char*msgid,
int partno, int nparts)
{
struct _subj_list **p;
#ifdef DEBUG
fprintf(stderr,
" Article '%s' contains '%s' part %d of %d.\n",
filename, new_subject, partno, nparts);
#endif
p=&subject_list;
while (*p)
{
if (0==strcmp((*p)->subject, subject) && (*p)->nparts==nparts)
{
add_article(&(*p)->partlist, filename, msgid, partno);
return;
}
p=&(*p)->next;
}
if (NULL==(*p=(struct _subj_list *)malloc(sizeof (struct _subj_list))))
error("*** Out of memory (malloc sub_list)\n");
(*p)->next=NULL;
if (NULL==((*p)->subject=(char *)malloc(strlen(subject)+1)))
error("*** Out of memory (malloc subject)\n");
strcpy((*p)->subject, subject);
(*p)->nparts=nparts;
(*p)->partlist=NULL;
add_article(&(*p)->partlist, filename, msgid, partno);
} /* store_part */
static void add_article(struct _part_list **partlist, char *filename,
char *msgid, int partno)
{
struct _part_list *p;
while (*partlist)
{
if ((*partlist)->partno == partno)
{
fprintf(stderr, "Duplicate article '%s' ignored\n", filename);
already_processed(msgid, TRUE, TRUE); /* don't parse this article again */
return;
}
else if ((*partlist)->partno > partno)
break; /* insert here */
partlist=&(*partlist)->next;
}
p=*partlist;
if (NULL==(*partlist=(struct _part_list *)malloc(sizeof (struct _part_list))))
error("*** Out of memory (malloc partlist)\n");
(*partlist)->next=p;
(*partlist)->partno=partno;
if (NULL==((*partlist)->filename=malloc(strlen(filename)+1)))
error("*** Out of memory (malloc filename)\n");
strcpy((*partlist)->filename, filename);
if (NULL==((*partlist)->msgid=malloc(strlen(msgid)+1)))
error("*** Out of memory (malloc msgid(partlist))\n");
strcpy((*partlist)->msgid, msgid);
} /* add_article */
static void output_results(void)
{
struct _subj_list *p;
struct _part_list *q;
int i;
char *cmdline=NULL;
for (p=subject_list; p; p=p->next)
{
for (i=1, q=p->partlist; i<=p->nparts; ++i, q=q->next)
if (!q || q->partno != i)
{
fprintf(stderr,
"Subject '%s' (%d parts) is incomplete.\n",
p->subject, p->nparts);
print_malformed(p);
goto next_subject;
}
if (q)
{
fprintf(stderr,
"Subject '%s' (%d parts) has too many parts.\n",
p->subject, p->nparts);
print_malformed(p);
goto next_subject;
}
if (option_dont_execute)
printf(SHELL_COMMAND_ECHO " ");
if (command)
printf("Executing %s for '%s'...\n", command, p->subject);
else
printf("Decoding '%s'...\n", p->subject);
if (option_dont_execute)
{
if (command)
fputs(command, stdout);
else
fputs(SHELL_COMMAND_COMMENT
" internal_decoder", stdout);
for (q=p->partlist; q; q=q->next)
printf(" %s", q->filename);
printf("\n");
}
else
{
if (command)
{
cmdline=(char *)malloc(strlen(command)+p->nparts*(strlen(p->partlist->filename)+5)+10);
if (cmdline==NULL)
error("*** out of memory (malloc cmdline)\n");
strcpy(cmdline, command);
for (q=p->partlist; q; q=q->next)
{
strcat(cmdline, " ");
strcat(cmdline, q->filename);
already_processed(q->msgid, TRUE, TRUE); /* don't parse this article again */
}
#if defined(DEBUG)
fprintf(stderr, "Executing: '%s'\n", cmdline);
#endif
system(cmdline);
free(cmdline);
}
else
{
begin_uucat();
for (q=p->partlist; q; q=q->next)
{
uucat_file(q->filename);
already_processed(q->msgid, TRUE, TRUE); /* don't parse this article again */
}
end_uucat();
}
}
next_subject:;
}
} /* output_results */
static void print_malformed(struct _subj_list *p)
{
struct _part_list *q;
int prev_part;
boolean in_range=FALSE;
int n_expected=0, n_unexpected=0;
if (option_verbose)
{
for (q=p->partlist; q; q=q->next)
fprintf(stderr,
" part %d: '%s'\n", q->partno, q->filename);
}
else
{
fprintf(stderr, "Available parts: %d",p->partlist->partno);
prev_part=p->partlist->partno;
if (1 <= p->partlist->partno && p->partlist->partno <= p->nparts)
++n_expected;
else
++n_unexpected;
for (q=p->partlist->next; q; q=q->next)
{
if (1 <= q->partno && q->partno <= p->nparts)
++n_expected;
else
++n_unexpected;
if (q->partno == ++prev_part)
in_range=TRUE;
else
{
if (in_range)
fprintf(stderr, "-%d", prev_part-1);
fprintf(stderr, ",%d", q->partno);
prev_part=q->partno;
in_range=FALSE;
}
}
if (in_range)
fprintf(stderr, "-%d", prev_part);
if (n_unexpected == 0)
fprintf(stderr, ". (%d part%s)\n", n_expected, (n_expected==1?"":"s"));
else
fprintf(stderr, ". (%d part%s + %d unexpected part%s)\n",
n_expected, (n_expected==1?"":"s"),
n_unexpected, (n_unexpected==1?"":"s"));
}
} /* print_malformed */
/* -- internal uucat decoder. Adapted from a public domain source ---- */
/*
*From: d84sp@efd.lth.se (Stefan Parmark)
Subject: Decoding pictures
Summary: uudecode
Date: 12 Aug 90 07:54:17 GMT
Organization: Lund Institute of Technology, Sweden
The other day I wrote a simple C program which I use when
uudecoding multi-part uuencoded files. It has worked for
all newsgroups I have tested so far. It saves you the effort
of having to edit the files. To use it, compile it
and to decode files, type
> uucat file1 file2 ... filen | uudecode
or
> cat file1 file2 ... filen | uucat | uudecode
or, if you already have concatenated them into one file
> uucat file | uudecode
. I place uucat in the public domain, and take no responsibility
for its usage.
*/
static char first = UFIRST, quote = UQUOTE;
static void begin_uucat(void)
{
uudecode = _popen("uudecode", "w");
echo_on = FALSE, started = FALSE, just_finished = FALSE;
line_length = 0, lines_to_go = 0;
uu_name[0]='\0';
if (option_save_descriptions)
{
description_file_name="$UUGRAB$.TMP";
if (NULL==(description_file=fopen(description_file_name, "w")))
error("Can't open description file '%s' for output.\n", description_file_name);
echo_description=TRUE;
}
else
echo_description=FALSE;
} /* begin_uucat */
static void end_uucat(void)
{
char *last_dot;
_pclose(uudecode);
if (option_save_descriptions)
{
fclose(description_file);
if (*uu_name=='\0') /* uu_name is set as a side effect of is_begin_line */
{
fprintf(stderr, "Description lost (no filename available)\n");
unlink(description_file_name);
}
else
{
/* replace the last extension with .des or append .des if none */
last_dot=strrchr(uu_name, '.');
if (!last_dot)
{
last_dot=&uu_name[strlen(uu_name)];
*last_dot='.';
}
*++last_dot='d';
*++last_dot='e';
*++last_dot='s';
*++last_dot='\0';
if (rename(description_file_name, uu_name))
{
fprintf(stderr, "Description lost: could not rename '%s' to '%s'.\n",
description_file_name, uu_name);
unlink(description_file_name);
}
}
}
} /* end_uucat */
static void uucat_file(char *filename)
{
FILE *infile;
char *s2, *s1, *s0, *tmp_s;
int length;
static char s[3 * (LENGTH + 1)];
if ((infile = fopen(filename, "r")) == NULL)
{
fprintf(stderr, "*** Can't open '%s' for input.\n", filename);
return;
}
s0 = s;
s1 = s0 + (LENGTH + 1);
s2 = s1 + (LENGTH + 1);
s0[0] = s1[0] = s2[0] = '\0'; /* Clear strings */
while (fgets(s0, LENGTH, infile) != NULL)
{
s0[LENGTH] = '\0'; /* Make sure string is terminated */
if (just_finished)
{
if (strncmp(s0, "size ", 5) == 0)
{
fputs(s0, uudecode);
s0[0] = '\0';
}
just_finished = FALSE;
}
if (!started)
{
if (is_begin_line(s0))
{
started = echo_on = TRUE;
line_length = 0;
lines_to_go = 0;
echo_description=FALSE;
}
}
else /* started */
{
length = strlen(s0);
if (line_length == 0)
line_length = length;
if (echo_on)
{
lines_to_go = 0;
if (s0[0] != first || length != line_length)
{
echo_on = FALSE;
lines_to_go = 2; /* Lines to go before 'end' is expected */
}
}
else /* !echo_on */
{
if (s0[0] == first && length == line_length)
echo_on = TRUE;
else if (lines_to_go > 0)
{
if (lines_to_go == 2)
{
if (s0[0] == ' ' || s0[0] == quote)
lines_to_go = 1;
else
lines_to_go = 0; /* Unexpected line, so break off */
}
else if (lines_to_go == 1)
{
if (strcmp(s0, "end\n") == 0)
{
fputs(s2, uudecode);
fputs(s1, uudecode);
fputs(s0, uudecode);
lines_to_go = 0; /* Done. Break off */
just_finished = TRUE;
started = FALSE;
}
else
lines_to_go = 0; /* Unexpected line, so break off */
}
}
}
}
if (echo_description)
fputs(s0, description_file);
if (echo_on)
{
fputs(s0, uudecode);
s0[0]='\0';
}
tmp_s = s2;
s2 = s1;
s1 = s0;
s0 = tmp_s;
}
fclose(infile);
} /* uucat_file */
/* check (thoroughly) if a line is the begin line of a uuencoded file */
/* SIDE EFFECT: store name of file to be uudecoded in uu_name which
must be an already allocated array of characters */
static int is_begin_line(char *s)
{
char *name_begin;
if (strncmp(s, "begin ", 6) != 0)
return FALSE;
s+=6;
while (isspace(*s)) ++s;
if (*s<'0' || *s>'7')
return FALSE;
while (*s>='0' && *s<='7') ++s;
if (*s != ' ') return FALSE;
while (isspace(*s)) ++s;
if (!*s)
return FALSE;
name_begin=s;
while (*s && !isspace(*s)) ++s;
if (*s=='\n')
{
strcpy(uu_name, name_begin);
uu_name[strlen(uu_name)]='\0'; /* remove trailing newline */
return TRUE;
}
else
return FALSE;
} /* is_begin_line */
/* ------------------------------------------------------------------- */
static void usage(void)
{
fprintf(stderr,
"Usage: uugrab [-a] [-c <command>] [-d] [-i <n>] [-n] [-v] files...\n"
" -a decode all files, even if there is no part number\n"
" -c execute <command> for each binary (default: decode binary)\n"
" -d save descriptions of binaries in separate files\n"
" -i ignore <n> fields at beginning of subject\n"
" -n don't do anything; just display what would be done\n"
" -v verbose: display some more messages\n"
"Hints: Use the -n option if unsure. Use -i 1 for comp.binaries.os2.\n"
" If all else fails, read the documentation.\n"
);
exit(1);
} /* usage */
int main(int argc, char *argv[])
{
int i;
#ifdef OS2
fprintf(stderr, "uugrab Version 1.6 (c)1992 by Harald Bögeholz\n");
#else
fprintf(stderr, "uugrab Version 1.6 (c)1992 by Harald Boegeholz\n");
#endif
for (i=1; i<argc; ++i)
{
if (argv[i][0] != '-')
break;
if (0==stricmp(argv[i], "-a"))
option_decode_all=TRUE;
else if (0==stricmp(argv[i], "-d"))
option_save_descriptions=TRUE;
else if (0==stricmp(argv[i], "-n"))
option_dont_execute=TRUE;
else if (0==stricmp(argv[i], "-v"))
option_verbose=TRUE;
else if (0 == stricmp(argv[i], "-i"))
{
if (++i<argc)
ignore_fields=atoi(argv[i]);
else
usage();
}
else if (0 == stricmp(argv[i], "-c"))
{
if (++i<argc)
command=argv[i];
else
usage();
}
else
usage();
}
if (i>=argc)
usage();
if (command && option_save_descriptions)
error("The -c and -d options are mutually exclusive.\n");
read_history();
for (; i<argc; ++i)
read_subjects(argv[i]);
output_results();
if (!option_dont_execute)
save_history();
return 0;
} /* main */