grwalter@watfun.uwaterloo.ca (Fred Walter) (12/18/90)
Posting-number: Volume 15, Issue 107 Submitted-by: grwalter@watfun.uwaterloo.ca (Fred Walter) Archive-name: newsbreak1.11/part01 The following is the lastest revision of newsbreak, a program that : * 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. The way I use it is to copy all the files from the newsgroup directory into a tmp directory and run newsbreak in there. IE. mkdir /tmp/grwalter/pc cd /tmp/grwalter/pc cp /usr/spool/news/comp/binaries/ibm/pc/* . newsbreak >& .news.out & When newsbreak is done the zoo files/etc are nicely put in subdirectories (with the name found in the Archive-name entry). ----cut here------ #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: newsbreak.c # Wrapped by grwalter@watfun on Sun Dec 9 23:36:38 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'newsbreak.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'newsbreak.c'\" else echo shar: Extracting \"'newsbreak.c'\" \(14584 characters\) sed "s/^X//" >'newsbreak.c' <<'END_OF_FILE' X#define VERSION "newsbreak 1.11 by G. R. Walter" X X/* X * newsbreak.c X * X * by G. R. Walter (Fred) December 30, 1988 X * X * USAGE: X * newsbreak [-a] X * If -a is used then all files will be processed. If -a is omitted then X * only files with an "Archive-name:" will be processed. X * X * DESCRIPTION: X * Takes a series of files which are shar files (strips any X * garbage at the start of the shar file) that have been posted to X * comp.{sources|binaries}.* and feeds them through sh. X * After they have been fed through sh the original files are X * deleted. Then any uuencoded files are uudecoded, after which X * the uuencoded files are also deleted. Special care is taken X * with files posted to comp.binaries.ibm.pc which use a non-standard X * format. X * X * TO COMPILE: X * Under BSD 4.3 X * cc newsbreak.c -o newsbreak.c X * Under System V (only those variants that allow -lbsd, which is X * required for scandir and alphasort) X * cc newsbreak.c -DSYSTEM_V -lbsd -o newsbreak.c X * X * NOTES: X * 1) This program assumes that all necessary shar files are in the X * current directory. It attempts to not delete stuff if it can't X * handle it (like when not all the parts of a multi-part uuencoded X * file are available). X * 2) When there are multiple parts to a uuencoded file, a maximum X * of 99 parts are currently handled. X * X * HISTORY: X * 1.00 - original version X * 1.01 - small enhancements/bug fixes X * 1.02 - now handle .zu's with > 9 parts correctly X * 1.03 - now check for ":\tshar\:Shell Archiver" when checking if a file X * is a shar archive X * - now handles files ending in .uu# X * 1.04 - now check for ": run sh on this file to unbundle" when checking X * if a file is a shar archive X * 1.05 - now check for "# This is a shell archive." when checking X * if a file is a shar archive X * - now prints out the version (and author name) when run X * 1.06 - now check for "Archive-name:" to see what directory the X * resulting files should be put in. NOTE: any parts after X * a "part*" section in the path are not mkdir'ed X * - now handles files ending in .zuu# X * - now handles files ending in .uu# properly X * - now doesn't attempt to process files starting in "." X * - now prints some useful info (so you know what it is doing) X * - now check for "# After you unpack everything" when checking X * if a file is a shar archive X * - make sure I don't try to uudecode directories X * - recursively descend directories when uudecoding X * 1.07 - added ifdef's around code needed so this compiles under System V X * - changes by ames!uts.amdahl.com!dwl10@mailrus (Dave Lowrey) X * 1.08 - now check for ": This is a shar archive." when checking X * if a file is a shar archive X * - now check for "# This is the first line of a \"shell archive\"" X * when checking if a file is a shar archive X * - build up a list of files in the current directory before unshar'ing X * - scan these files to see which ones should be unshar'ed and try X * to determine the best ordering for unshar'ing (using the secondary X * header "Archive-name:" if it exists, otherwise using file name) X * - print what directory is being searched for uuencoded files X * - print what is being uudecoded X * 1.09 - added code to force creation of all necessary subdirectories X * - based on code supplied by michel@etl.go.jp (Michel Pasquier) X * 1.10 - now check for "# type sh " when checking X * if a file is a shar archive X * - now check for "# To recover, type \"sh archive\"" when checking X * if a file is a shar archive X * - now handle .puu# X * - effectively do a caseless strncmp() on "part" in unshar() so that X * things like "Archive-name: nethack3p9/Part01" are properly handled X * 1.11 - added special case handling for postings to comp.binaries.ibm.pc X */ X X#include <stdio.h> X#include <ctype.h> X#include <sys/types.h> X#include <sys/file.h> X#include <sys/stat.h> X#include <sys/dir.h> X#ifndef SYSTEM_V Xchar *getwd(); X#else X# include <dirent.h> Xchar *getcwd(); X#endif X Xchar *malloc(); Xchar *strcpy(); Xchar *sprintf(); X Xtypedef struct { X char *filename; X char *archivename; X} Name; X Xchar ArchiveName[200]; X X#define AN_ARCHIVE(BUF) \ X( \ X (!strncmp(BUF, "#!/bin/sh", 9)) \ X|| (!strncmp(BUF, "#! /bin/sh", 10)) \ X|| (!strncmp(BUF, "# This is a shell archive.", 26)) \ X|| (!strncmp(BUF, ": This is a shar archive.", 25)) \ X|| (!strncmp(BUF, ":\tshar:\tShell Archiver", 22)) \ X|| (!strncmp(BUF, ": run sh on this file to unbundle", 33)) \ X|| (!strncmp(BUF, "# After you unpack everything", 29)) \ X|| (!strncmp(BUF, "# This is the first line of a \"shell archive\"", 45)) \ X|| (!strncmp(BUF, "# type sh ", 13)) \ X|| (!strncmp(BUF, "# To recover, type \"sh archive\"", 30)) \ X) X X#define COMBINE ".newsbreak.combine" X Xmain(argc, argv) X int argc; X char **argv; X{ X#ifndef SYSTEM_V X struct direct **dp; X#else X struct dirent **dp; X#endif X struct stat stat_buf; X int size; X int i; X int j; X Name *array; X int all_flag = 0; X X int Select(); X extern int alphasort(); X int compare(); X void unshar(); X void uudecode(); X X fprintf(stderr, "%s\n", VERSION); X X if (argc > 1) X if (!strcmp(argv[1], "-a")) X all_flag = -1; X X /* X * Count the sharfiles in the current directory. If there are any, put X * the filenames and archive-names (if any) into an array and sort it. X * Then unshar. (This code assumes that the current directory contents X * don't change underneath you.) X */ X size = scandir(".", &dp, Select, alphasort); X if (size > 0) { X array = (Name *) malloc((unsigned) (sizeof(Name) * size)); X for (i = 0, j = 0; i < size; i++) { X if (stat(dp[i]->d_name, &stat_buf)) /* can't stat !?!?!? */ X continue; X X if ((stat_buf.st_mode & S_IFDIR)) /* a directory */ X continue; X X if (has_an_archive_name(dp[i]->d_name) || all_flag) { X array[j].filename = X malloc((unsigned) (strlen(dp[i]->d_name) + 1)); X strcpy(array[j].filename, dp[i]->d_name); X array[j].archivename = X malloc((unsigned) (strlen(ArchiveName) + 1)); X strcpy(array[j].archivename, ArchiveName); X j++; X } X } X size = j; X if (size > 0) { X fprintf(stderr, "\nNow performing the unshar pass.\n"); X X qsort((char *) array, size, (int) sizeof(Name), compare); X X /* now unshar everything */ X for (i = 0; i < size; i++) X unshar(array[i].filename, array[i].archivename); X } X fprintf(stderr, "\nNow performing the uudecode pass.\n"); X X uudecode(".", 0); X } X /* X * In theory I should free all allocated memory, but it will be free'd X * upon exitting. X */ X exit(0); X} X X/* X * create_subpath - recursively create subpath X */ X Xvoid Xcreate_subpath(dir, subpath) X char *dir; X char *subpath; X{ X char *p; X char *newdir; X X for (p = subpath; *p != '\0' && *p != '/'; p++); X X if (*p == '/') { /* was a sub-directory and not a filename */ X *p++ = '\0'; X newdir = malloc((unsigned) (strlen(dir) + 1 + strlen(subpath) + 1)); X sprintf(newdir, "%s/%s", dir, subpath); X /* X * If it doesn't exist then create it. X */ X if (access(newdir, F_OK) < 0) { X if (mkdir(newdir, 0777) < 0) { X fprintf(stderr, "Couldn't mkdir %s\n", newdir); X return; X } X } X create_subpath(newdir, p); X free(newdir); X } X} X X/* X * ensure_existance_of_subdirs - ensure existance of necessary sub-directories X * X * Search for destination file or path and extract its full name X * then create necessary sub-directories. X */ X X#define NOT_END(P) \ X(*P != ' ' && *P != '\'' && *P != '\"' && *P != '\n' && *P != '&' && *P != '\0') X Xvoid Xensure_existance_of_subdirs(p, dir) X char *p; X char *dir; X{ X char *subdirs; X X for (; *p != '>' && *p != '\0'; p++); /* Get to start of path. */ X if (*p == '\0') X return; X for (p++; (*p == ' ' || *p == '\'' || *p == '\"') && *p != '\0'; p++); X if (*p == '\0') X return; X X subdirs = p; /* Get to end of path. */ X for (; NOT_END(p); p++); X *p = '\0'; X X create_subpath(dir, subdirs); X} X Xvoid Xunshar(name, archivename) X char *name; X char *archivename; X{ X FILE *fin; X FILE *fout; X char buf[200]; X char dir[200]; X char *part = NULL; X char *p; X char tmp[4]; X int i; X X fprintf(stderr, "Attempting to unshar %s\n", name); X fin = fopen(name, "r"); X if (fin == NULL) /* file doesn't exist !? */ X return; X X strcpy(dir, "."); /* setup directory to use */ X if (archivename[0] != '\0') { X strcpy(dir, archivename); X for (p = dir; *p != NULL; p++) { X if (*p == '/') { X *p = NULL; X for (i = 0; i < 4; i++) { X if (isascii(p[i + 1]) && isupper(p[i + 1])) X tmp[i] = tolower(p[i + 1]); X else X tmp[i] = p[i + 1]; X if (tmp[i] == '\0') X break; X } X if (!strncmp(tmp, "part", 4)) { X part = p + 1; X break; X } X if (access(dir, F_OK) < 0) X if (mkdir(dir, 0777) < 0) X goto ABORT_ATTEMPT; X *p = '/'; X } X } X if (access(dir, F_OK) < 0) { X if (mkdir(dir, 0777) < 0) { X ABORT_ATTEMPT: X fprintf(stderr, "Couldn't mkdir %s\n", dir); X fprintf(stderr, "Aborting this attempt\n"); X fclose(fin); X return; X } X } X } X fprintf(stderr, "unsharing into directory \"%s\"\n", dir); X X for (;;) { X if (fgets(buf, 200, fin) == NULL) { /* not a shar file !? */ X fclose(fin); X return; X } X if (!strncmp(buf, "Newsgroups: comp.binaries.ibm.pc", 32)) { X if (part != NULL) { X fclose(fin); X sprintf(buf, "mv %s %s/%s%s", name, dir, part, COMBINE); X (void) system(buf); X return; X } X } X if (AN_ARCHIVE(buf)) X break; X } X X sprintf(buf, "%s/.unshar.temp.file", dir); X fout = fopen(buf, "w"); X while (fgets(buf, 200, fin) != NULL) { X fprintf(fout, "%s", buf); X /* X * For each source archived ensure existance of necessary X * sub-directories. X */ X if (!strncmp(buf, "sed", 3) || !strncmp(buf, "cat", 3)) X ensure_existance_of_subdirs(buf, dir); X } X fclose(fout); X fclose(fin); X X sprintf(buf, "cd %s; sh .unshar.temp.file", dir); X if (system(buf) == 0) { X (void) unlink(name); X } else { X fprintf(stderr, "exit status non-zero, not deleting %s\n", name); X } X X sprintf(buf, "rm %s/.unshar.temp.file", dir); X (void) system(buf); X} X Xvoid Xuudecode(name, level) X char *name; X int level; X{ X#ifndef SYSTEM_V X struct direct **dp; X#else X struct dirent **dp; X#endif X FILE *file; X char buf[200]; X char name_buf[200]; X char path[200]; X char *p; X struct stat stat_buf; X char digit; X int i; X int size; X X int Select(); X extern int alphasort(); X X if (stat(name, &stat_buf)) /* can't stat !?!?!?! */ X return; X X if ((stat_buf.st_mode & S_IFDIR)) { X /* uudecode everything in this directory */ X#ifndef SYSTEM_V X if (!getwd(path)) X return; X#else X if (!getcwd(path, 200)) X return; X#endif X size = scandir(name, &dp, Select, alphasort); X if (size <= 0) X return; X X if (chdir(name)) X return; X X level++; X if (level == 1) X fprintf(stderr, "uudecoding in directory \"%s\"\n", path); X else X fprintf(stderr, "uudecoding in directory \"%s/%s\"\n", path, name); X for (i = 0; i < size; i++) X uudecode(dp[i]->d_name, level); X (void) chdir(path); X if (level > 1) X fprintf(stderr, "uudecoding in directory \"%s\"\n", path); X return; X } X /* X * First combine any files that end in COMBINE. X */ X p = name + strlen(name) - strlen(COMBINE); X if (p >= name) { X if (!strcmp(p, COMBINE)) { X sprintf(buf, "cat *%s | sed '/^END/,/^BEGIN/d'| uudecode", COMBINE); X if (system(buf) == 0) { X sprintf(buf, "rm *%s", COMBINE); X (void) system(buf); X } X return; X } X } X /* X * If the file ends in ".uue" or ".zuu" ".puu" or ".uu" just uudecode it. X * Handle ".zuu#", ".puu#", ".pu#", ".zu#" and ".uu#" where # is a X * number. X */ X p = name + strlen(name) - 4; X if (((strcmp(p, ".uue") && strcmp(p, ".zuu") && X strcmp(p, ".puu") && strcmp(p + 1, ".uu")))) { X p += 3; X while (isdigit(*p)) X p--; X X digit = p[1]; X p[1] = '\0'; X p -= 2; X if (!strcmp(p, ".uu") || !strcmp(p, ".zu") || !strcmp(p, ".pu")) { X if (digit == '0') { X sprintf(buf, "cat %s* | uudecode", name); X } else { X sprintf(name_buf, "%s10", name); X file = fopen(name_buf, "r"); X if (file == NULL) { X sprintf(buf, "cat %s? | uudecode", name); X } else { X fclose(file); X sprintf(buf, "cat %s? %s?? | uudecode", name, name); X } X } X } else if (strcmp(p - 1, ".zuu") && strcmp(p - 1, ".puu")) { X return; X } X } X sprintf(buf, "cat %s* | uudecode", name); X fprintf(stderr, "%s\n", buf); X if (system(buf) == 0) { X sprintf(buf, "rm %s*", name); X (void) system(buf); X } else { X fprintf(stderr, "exit status non-zero, not deleting file(s)\n"); X } X} X Xint Xcompare(element1, element2) X Name *element1; X Name *element2; X{ X int result; X X result = strcmp(element1->archivename, element2->archivename); X if (result == 0) X result = strcmp(element1->filename, element2->filename); X X return (result); X} X X/* X * has_an_archive_name - return -1 if has an archive name, 0 otherwise. X * - as well, set the global variable ArchiveName X */ X Xint Xhas_an_archive_name(name) X char *name; X{ X FILE *fin; X char buf[200]; X X ArchiveName[0] = '\0'; X X fin = fopen(name, "r"); X if (fin == NULL) /* file doesn't exist !? */ X return (0); X X for (;;) { X if (fgets(buf, 200, fin) == NULL) { X break; X } else if (strncmp(buf, "Archive-name:", 13) == 0) { X sscanf(buf, "Archive-name: %s", ArchiveName); X fclose(fin); X return (-1); X } X } X fclose(fin); X return (0); X} X Xint XSelect(dp) X#ifndef SYSTEM_V X struct direct *dp; X#else X struct dirent *dp; X#endif X{ X if (dp->d_name[0] != '.') X return (-1); X else X return (0); X} END_OF_FILE if test 14584 -ne `wc -c <'newsbreak.c'`; then echo shar: \"'newsbreak.c'\" unpacked with wrong size! fi # end of 'newsbreak.c' fi echo shar: End of shell archive. exit 0