home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
misc
/
volume17
/
newsbreak
/
part01
/
newsbreak.c
Wrap
C/C++ Source or Header
|
1991-04-04
|
18KB
|
677 lines
#define VERSION "newsbreak 1.12 by G. R. Walter"
/*
* newsbreak.c
*
* by G. R. Walter (Fred) December 30, 1988
*
* USAGE:
* newsbreak [-a]
* Default action is to only process files that contain the line
* "Archive-name:" - this is used to create the subdirectory that
* the shar files are unshared/etc into.
*
* If -a is used then all files will be processed. This is needed
* for postings to groups such as alt.sources, or when dealing with
* entries at some archive sites (the program is stored as lots
* of shar files).
*
* DESCRIPTION:
* Takes a series of files which are shar files (strips any
* garbage at the start of the shar file) that have been posted to
* comp.{sources|binaries}.* and feeds them through sh.
* After they have been fed through sh the original files are
* deleted. Then any uuencoded files are uudecoded, after which
* the uuencoded files are also deleted. Special care is taken
* with files posted to comp.binaries.ibm.pc which use a non-standard
* format.
*
* TO COMPILE:
* Under BSD 4.3
* cc newsbreak.c -o newsbreak
* Under System V
* cc -DSYSTEM_V newsbreak.c -lbsd -o newsbreak
* Under Xenix
* cc -DXENIX newsbreak.c -lx -o newsbreak
*
* NOTES:
* 1) This program assumes that all necessary shar files are in the
* current directory. It attempts to not delete stuff if it can't
* handle it (like when not all the parts of a multi-part uuencoded
* file are available).
* 2) When there are multiple parts to a uuencoded file, a maximum
* of 99 parts are currently handled.
*
* HISTORY:
* 1.00 - original version
* 1.01 - small enhancements/bug fixes
* 1.02 - now handle .zu's with > 9 parts correctly
* 1.03 - now check for ":\tshar\:Shell Archiver" when checking if a file
* is a shar archive
* - now handles files ending in .uu#
* 1.04 - now check for ": run sh on this file to unbundle" when checking
* if a file is a shar archive
* 1.05 - now check for "# This is a shell archive." when checking
* if a file is a shar archive
* - now prints out the version (and author name) when run
* 1.06 - now check for "Archive-name:" to see what directory the
* resulting files should be put in. NOTE: any parts after
* a "part*" section in the path are not mkdir'ed
* - now handles files ending in .zuu#
* - now handles files ending in .uu# properly
* - now doesn't attempt to process files starting in "."
* - now prints some useful info (so you know what it is doing)
* - now check for "# After you unpack everything" when checking
* if a file is a shar archive
* - make sure I don't try to uudecode directories
* - recursively descend directories when uudecoding
* 1.07 - added ifdef's around code needed so this compiles under System V
* - changes by ames!uts.amdahl.com!dwl10@mailrus (Dave Lowrey)
* 1.08 - now check for ": This is a shar archive." when checking
* if a file is a shar archive
* - now check for "# This is the first line of a \"shell archive\""
* when checking if a file is a shar archive
* - build up a list of files in the current directory before unshar'ing
* - scan these files to see which ones should be unshar'ed and try
* to determine the best ordering for unshar'ing (using the secondary
* header "Archive-name:" if it exists, otherwise using file name)
* - print what directory is being searched for uuencoded files
* - print what is being uudecoded
* 1.09 - added code to force creation of all necessary subdirectories
* - based on code supplied by michel@etl.go.jp (Michel Pasquier)
* 1.10 - now check for "# type sh " when checking
* if a file is a shar archive
* - now check for "# To recover, type \"sh archive\"" when checking
* if a file is a shar archive
* - now handle .puu#
* - effectively do a caseless strncmp() on "part" in unshar() so that
* things like "Archive-name: nethack3p9/Part01" are properly handled
* 1.11 - added special case handling for postings to comp.binaries.ibm.pc
* (these aren't shar files)
* 1.12 - ported to XENIX
*/
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>
#ifdef XENIX
# include <sys/ndir.h>
# include <sys/dirent.h>
# include <errno.h>
char *getcwd();
#endif
#ifdef SYSTEM_V
# include <sys/dir.h>
# include <dirent.h>
char *getcwd();
#endif
#ifndef XENIX
# ifndef SYSTEM_V
# define OTHER
# include <sys/dir.h>
char *getwd();
# endif
#endif
#ifdef XENIX
# define F_OK (0)
#endif
char *malloc();
char *strcpy();
char *sprintf();
typedef struct {
char *filename;
char *archivename;
} Name;
char ArchiveName[200];
#define AN_ARCHIVE(BUF) \
( \
(!strncmp(BUF, "#!/bin/sh", 9)) \
|| (!strncmp(BUF, "#! /bin/sh", 10)) \
|| (!strncmp(BUF, "# This is a shell archive.", 26)) \
|| (!strncmp(BUF, ": This is a shar archive.", 25)) \
|| (!strncmp(BUF, ":\tshar:\tShell Archiver", 22)) \
|| (!strncmp(BUF, ": run sh on this file to unbundle", 33)) \
|| (!strncmp(BUF, "# After you unpack everything", 29)) \
|| (!strncmp(BUF, "# This is the first line of a \"shell archive\"", 45)) \
|| (!strncmp(BUF, "# type sh ", 13)) \
|| (!strncmp(BUF, "# To recover, type \"sh archive\"", 30)) \
)
#define COMBINE "~~"
main(argc, argv)
int argc;
char **argv;
{
#ifdef SYSTEM_V
struct dirent **dp;
#else
struct direct **dp;
#endif
struct stat stat_buf;
int size;
int i;
int j;
Name *array;
int all_flag = 0;
int Select();
int alphasort();
int scandir();
int compare();
void unshar();
void uudecode();
fprintf(stderr, "%s\n", VERSION);
if (argc > 1)
if (!strcmp(argv[1], "-a"))
all_flag = -1;
/*
* Count the sharfiles in the current directory. If there are any, put
* the filenames and archive-names (if any) into an array and sort it.
* Then unshar. (This code assumes that the current directory contents
* don't change underneath you.)
*/
size = scandir(".", &dp, Select, alphasort);
if (size > 0) {
array = (Name *) malloc((unsigned) (sizeof(Name) * size));
for (i = 0, j = 0; i < size; i++) {
if (stat(dp[i]->d_name, &stat_buf)) /* can't stat !?!?!? */
continue;
if ((stat_buf.st_mode & S_IFDIR)) /* a directory */
continue;
if (has_an_archive_name(dp[i]->d_name) || all_flag) {
array[j].filename =
malloc((unsigned) (strlen(dp[i]->d_name) + 1));
strcpy(array[j].filename, dp[i]->d_name);
array[j].archivename =
malloc((unsigned) (strlen(ArchiveName) + 1));
strcpy(array[j].archivename, ArchiveName);
j++;
}
}
size = j;
if (size > 0) {
fprintf(stderr, "\nNow performing the unshar pass.\n");
qsort((char *) array, size, (int) sizeof(Name), compare);
/* now unshar everything */
for (i = 0; i < size; i++)
unshar(array[i].filename, array[i].archivename);
}
fprintf(stderr, "\nNow performing the uudecode pass.\n");
uudecode(".", 0);
}
/*
* In theory I should free all allocated memory, but it will be free'd
* upon exitting.
*/
exit(0);
}
/*
* create_subpath - recursively create subpath
*/
void
create_subpath(dir, subpath)
char *dir;
char *subpath;
{
char *p;
char *newdir;
for (p = subpath; *p != '\0' && *p != '/'; p++);
if (*p == '/') { /* was a sub-directory and not a filename */
*p++ = '\0';
newdir = malloc((unsigned) (strlen(dir) + 1 + strlen(subpath) + 1));
sprintf(newdir, "%s/%s", dir, subpath);
/*
* If it doesn't exist then create it.
*/
if (access(newdir, F_OK) < 0) {
if (mkdir(newdir, 0777) < 0) {
fprintf(stderr, "Couldn't mkdir %s\n", newdir);
return;
}
}
create_subpath(newdir, p);
free(newdir);
}
}
/*
* ensure_existance_of_subdirs - ensure existance of necessary sub-directories
*
* Search for destination file or path and extract its full name
* then create necessary sub-directories.
*/
#define NOT_END(P) \
(*P != ' ' && *P != '\'' && *P != '\"' && *P != '\n' && *P != '&' && *P != '\0')
void
ensure_existance_of_subdirs(p, dir)
char *p;
char *dir;
{
char *subdirs;
for (; *p != '>' && *p != '\0'; p++); /* Get to start of path. */
if (*p == '\0')
return;
for (p++; (*p == ' ' || *p == '\'' || *p == '\"') && *p != '\0'; p++);
if (*p == '\0')
return;
subdirs = p; /* Get to end of path. */
for (; NOT_END(p); p++);
*p = '\0';
create_subpath(dir, subdirs);
}
void
unshar(name, archivename)
char *name;
char *archivename;
{
FILE *fin;
FILE *fout;
char buf[200];
char dir[200];
char *part = NULL;
char *p;
char tmp[4];
int i;
fprintf(stderr, "Attempting to unshar %s\n", name);
fin = fopen(name, "r");
if (fin == (FILE *) NULL) /* file doesn't exist !? */
return;
strcpy(dir, "."); /* setup directory to use */
if (archivename[0] != '\0') {
strcpy(dir, archivename);
for (p = dir; *p != '\0'; p++) {
if (*p == '/') {
*p = '\0';
for (i = 0; i < 4; i++) {
if (isascii(p[i + 1]) && isupper(p[i + 1]))
tmp[i] = tolower(p[i + 1]);
else
tmp[i] = p[i + 1];
if (tmp[i] == '\0')
break;
}
if (!strncmp(tmp, "part", 4)) {
part = p + 1;
break;
}
if (access(dir, F_OK) < 0)
if (mkdir(dir, 0777) < 0)
goto ABORT_ATTEMPT;
*p = '/';
}
}
if (access(dir, F_OK) < 0) {
if (mkdir(dir, 0777) < 0) {
ABORT_ATTEMPT:
fprintf(stderr, "Couldn't mkdir %s\n", dir);
fprintf(stderr, "Aborting this attempt\n");
fclose(fin);
return;
}
}
}
fprintf(stderr, "unsharing into directory \"%s\"\n", dir);
for (;;) {
if (fgets(buf, 200, fin) == NULL) { /* not a shar file !? */
fclose(fin);
return;
}
if (!strncmp(buf, "Newsgroups: comp.binaries.ibm.pc", 32)) {
if (part != NULL) {
fclose(fin);
sprintf(buf, "mv %s %s/%s%s", name, dir, part, COMBINE);
(void) system(buf);
return;
}
}
if (AN_ARCHIVE(buf))
break;
}
sprintf(buf, "%s/.unshar.temp.file", dir);
fout = fopen(buf, "w");
while (fgets(buf, 200, fin) != NULL) {
fprintf(fout, "%s", buf);
/*
* For each source archived ensure existance of necessary
* sub-directories.
*/
if (!strncmp(buf, "sed", 3) || !strncmp(buf, "cat", 3))
ensure_existance_of_subdirs(buf, dir);
}
fclose(fout);
fclose(fin);
sprintf(buf, "cd %s; sh .unshar.temp.file", dir);
if (system(buf) == 0) {
(void) unlink(name);
} else {
fprintf(stderr, "exit status non-zero, not deleting %s\n", name);
}
sprintf(buf, "rm %s/.unshar.temp.file", dir);
(void) system(buf);
}
void
uudecode(name, level)
char *name;
int level;
{
#ifdef SYSTEM_V
struct dirent **dp;
#else
struct direct **dp;
#endif
FILE *file;
char buf[200];
char name_buf[200];
char path[200];
char *p;
struct stat stat_buf;
char digit;
int i;
int size;
int scandir();
int Select();
int alphasort();
if (stat(name, &stat_buf)) /* can't stat !?!?!?! */
return;
if ((stat_buf.st_mode & S_IFDIR)) {
/* uudecode everything in this directory */
#ifdef OTHER
if (!getwd(path))
return;
#else
if (!getcwd(path, 200))
return;
#endif
size = scandir(name, &dp, Select, alphasort);
if (size <= 0)
return;
if (chdir(name))
return;
level++;
if (level == 1)
fprintf(stderr, "uudecoding in directory \"%s\"\n", path);
else
fprintf(stderr, "uudecoding in directory \"%s/%s\"\n", path, name);
for (i = 0; i < size; i++)
uudecode(dp[i]->d_name, level);
(void) chdir(path);
if (level > 1)
fprintf(stderr, "uudecoding in directory \"%s\"\n", path);
return;
}
/*
* First combine any files that end in COMBINE.
*/
p = name + strlen(name) - strlen(COMBINE);
if (p >= name) {
if (!strcmp(p, COMBINE)) {
sprintf(buf, "cat *%s | sed '/^END/,/^BEGIN/d'| uudecode", COMBINE);
if (system(buf) == 0) {
sprintf(buf, "rm *%s", COMBINE);
(void) system(buf);
}
return;
}
}
/*
* If the file ends in ".uue" or ".zuu" ".puu" or ".uu" just uudecode it.
* Handle ".zuu#", ".puu#", ".pu#", ".zu#" and ".uu#" where # is a
* number.
*/
p = name + strlen(name) - 4;
if (((strcmp(p, ".uue") && strcmp(p, ".zuu") &&
strcmp(p, ".puu") && strcmp(p + 1, ".uu")))) {
p += 3;
while (isdigit(*p))
p--;
digit = p[1];
p[1] = '\0';
p -= 2;
if (!strcmp(p, ".uu") || !strcmp(p, ".zu") || !strcmp(p, ".pu")) {
if (digit == '0') {
sprintf(buf, "cat %s* | uudecode", name);
} else {
sprintf(name_buf, "%s10", name);
file = fopen(name_buf, "r");
if (file == (FILE *) NULL) {
sprintf(buf, "cat %s? | uudecode", name);
} else {
fclose(file);
sprintf(buf, "cat %s? %s?? | uudecode", name, name);
}
}
} else if (strcmp(p - 1, ".zuu") && strcmp(p - 1, ".puu")) {
return;
}
}
sprintf(buf, "cat %s* | uudecode", name);
fprintf(stderr, "%s\n", buf);
if (system(buf) == 0) {
sprintf(buf, "rm %s*", name);
(void) system(buf);
} else {
fprintf(stderr, "exit status non-zero, not deleting file(s)\n");
}
}
int
compare(element1, element2)
Name *element1;
Name *element2;
{
int result;
result = strcmp(element1->archivename, element2->archivename);
if (result == 0)
result = strcmp(element1->filename, element2->filename);
return (result);
}
/*
* has_an_archive_name - return -1 if has an archive name, 0 otherwise.
* - as well, set the global variable ArchiveName
*/
int
has_an_archive_name(name)
char *name;
{
FILE *fin;
char buf[200];
ArchiveName[0] = '\0';
fin = fopen(name, "r");
if (fin == (FILE *) NULL) /* file doesn't exist !? */
return (0);
for (;;) {
if (fgets(buf, 200, fin) == NULL) {
break;
} else if (strncmp(buf, "Archive-name:", 13) == 0) {
sscanf(buf, "Archive-name: %s", ArchiveName);
fclose(fin);
return (-1);
}
}
fclose(fin);
return (0);
}
int
Select(dp)
#ifdef SYSTEM_V
struct dirent *dp;
#else
struct direct *dp;
#endif
{
if (dp->d_name[0] != '.')
return (-1);
else
return (0);
}
#ifndef OTHER
/*
* alphasort and scandir by rsalz.
*/
/* Initial guess at directory size. */
#define INITIAL_SIZE 30
/* A convenient shorthand. */
typedef struct direct ENTRY;
/* Linked in later. */
extern char *malloc();
extern char *realloc();
extern char *strcpy();
int
alphasort(d1, d2)
ENTRY **d1;
ENTRY **d2;
{
return(strcmp(d1[0]->d_name, d2[0]->d_name));
}
int
scandir(name, list, selector, sorter)
char *name;
ENTRY ***list;
int (*selector)();
int (*sorter)();
{
ENTRY **names;
ENTRY *E;
DIR *Dp;
int i;
int size;
/* Get initial list space and open directory. */
size = INITIAL_SIZE;
names = (ENTRY **)malloc(size * sizeof names[0]);
if (names == (ENTRY **) NULL)
return(-1);
Dp = opendir(name);
if (Dp == (DIR *) NULL)
return(-1);
/* Read entries in the directory. */
for (i = 0; E = readdir(Dp); )
if (selector == 0 || (*selector)(E)) {
/* User wants them all, or he wants this one. */
if (++i >= size) {
size <<= 1;
names = (ENTRY **)realloc((char *)names, size * sizeof names[0]);
if (names == (ENTRY **) NULL) {
closedir(Dp);
return(-1);
}
}
/* Copy the entry. */
names[i - 1] = (ENTRY *)malloc(DIRSIZ(E));
if (names[i - 1] == (ENTRY *) NULL) {
closedir(Dp);
return(-1);
}
names[i - 1]->d_ino = E->d_ino;
names[i - 1]->d_reclen = E->d_reclen;
names[i - 1]->d_namlen = E->d_namlen;
(void)strcpy(names[i - 1]->d_name, E->d_name);
}
/* Close things off. */
names[i] = (ENTRY *)NULL;
*list = names;
closedir(Dp);
/* Sort? */
if (i && sorter)
qsort((char *)names, i, sizeof names[0], sorter);
return(i);
}
#endif
#ifdef XENIX
/*
* 4.2BSD mkdir simulation from cnews
*/
/* system call returns */
#define SYS_OK 0
#define SYS_ERR (-1)
#define UMASK_MASK 0777
#define STRLEN(s) (sizeof (s) - 1) /* s must be a char array */
int
mkdir(dir, mode)
char *dir;
int mode;
{
char *cbuf = malloc((unsigned)STRLEN("mkdir ") + strlen(dir) + 1);
register int oldmask, ret;
if (cbuf == NULL) {
errno = ENOMEM; /* kludge */
return SYS_ERR;
}
oldmask = umask(0);
(void) umask(~(mode & ~oldmask) & UMASK_MASK);
(void) sprintf(cbuf, "mkdir %s", dir);
ret = (system(cbuf) != 0? SYS_ERR: SYS_OK);
if (ret == SYS_ERR)
errno = EINVAL; /* kludge */
(void) umask(oldmask);
free(cbuf);
return ret;
}
#endif