home *** CD-ROM | disk | FTP | other *** search
- Subject: v19i065: NN, a Usenet news reader, Part04/15
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: mcvax!tidk!storm@uunet.UU.NET (Kim F. Storm)
- Posting-number: Volume 19, Issue 65
- Archive-name: nn/part04
-
- #!/bin/sh
- # this is part 4 of a multipart archive
- # do not concatenate these parts, unpack them in order with /bin/sh
- # file folder.c continued
- #
- CurArch=4
- if test ! -r s2_seq_.tmp
- then echo "Please unpack part 1 first!"
- exit 1; fi
- ( read Scheck
- if test "$Scheck" != $CurArch
- then echo "Please unpack part $Scheck next!"
- exit 1;
- else exit 0; fi
- ) < s2_seq_.tmp || exit 1
- echo "x - Continuing file folder.c"
- sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' >> folder.c
- X
- X if (*path == '|') return -1; /* no completion for pipes */
- X
- X if (*path == '+' || *path == '~') {
- X if (!expand_file_name(nbuf, path))
- X return 0; /* no completions */
- X } else
- X strcpy(nbuf, path);
- X
- X if (base = strrchr(nbuf, '/')) {
- X if (base == nbuf) {
- X dir = "/";
- X base++;
- X } else {
- X *base++ = NUL;
- X dir = nbuf;
- X }
- X } else {
- X base = nbuf;
- X dir = ".";
- X }
- X
- X tail_offset = strlen(base);
- X
- X dir_in_use = list_directory(dir, base);
- X
- X return dir_in_use;
- X }
- X
- X if (index)
- X return help_directory();
- X
- X if (!next_directory(buffer)) return 0;
- X
- X strcpy(tail, buffer+tail_offset);
- X
- X return 1;
- X}
- X
- X
- X/*
- X * read file names in directory 'dir' starting with 'prefix'
- X *
- X * this could be speeded up by an order of magnitude by
- X * reading the directory directly into an array and sort
- X * it internally.
- X *
- X */
- X
- Xstatic char dir_path[FILENAME], *dir_tail;
- X
- X#ifndef HAVE_DIRECTORY
- X
- Xstatic FILE *dirf;
- Xstatic int prefix_lgt;
- X
- Xstatic list_directory(dir, prefix)
- Xchar *dir, *prefix;
- X{
- X sprintf(dir_path, "cd %s && echo %s* 2>/dev/null", dir, prefix);
- X prefix_lgt = strlen(prefix);
- X
- X if ((dirf = popen(dir_path, "r")) == NULL) return 0;
- X
- X dir_tail = dir_path;
- X while (*dir_tail++ = *dir++);
- X dir_tail[-1] = '/';
- X
- X return 1;
- X}
- X
- Xstatic next_directory(buffer)
- Xchar *buffer;
- X{
- X register char *cp;
- X register int c;
- X
- X cp = buffer;
- X while ((c = getc(dirf)) != EOF && (c != SP) && (c != NL))
- X *cp++ = c;
- X
- X if (cp != buffer) {
- X *cp = NUL;
- X if (strcmp(buffer + prefix_lgt, "*")) {
- X
- X strcpy(dir_tail, buffer);
- X if (file_exist(dir_path, "d")) {
- X *cp++ = '/';
- X *cp = NUL;
- X }
- X
- X return 1;
- X }
- X
- X }
- X
- X close_directory();
- X return 0;
- X}
- X
- Xhelp_directory()
- X{
- X return 0;
- X}
- X
- Xstatic close_directory()
- X{
- X if (dirf) {
- X pclose(dirf);
- X dirf = NULL;
- X }
- X}
- X#else /* HAVE_DIRECTORY */
- X
- Xstatic string_marker str_mark;
- Xstatic char **completions = NULL;
- Xstatic char **comp_iterator;
- Xstatic char **comp_help;
- X
- X/*
- X * list_directory scans the directory twice; first time to find out how
- X * many matches there are, and second time to save the names, after
- X * sufficient memory have been allocated to store it all.
- X */
- X
- Xstatic sort_directory(f1, f2) /* Used by qsort */
- X register char **f1;
- X register char **f2;
- X{
- X return strcmp(*f1, *f2);
- X}
- X
- Xstatic list_directory(dir, prefix)
- Xchar *dir, *prefix;
- X{
- X DIR *dirp;
- X register Direntry *dp;
- X register char *cp;
- X register char **comp;
- X int pflen = strlen(prefix);
- X unsigned nmatch = 1; /* No. of completions plus one */
- X
- X if ((dirp = opendir(dir)) == NULL)
- X return 0; /* tough luck */
- X
- X while ((dp = readdir(dirp)) != NULL) {
- X cp = dp->d_name;
- X if (*cp == '.' && (cp[1] == '\0' || (cp[1] == '.' && cp[2] == '\0')))
- X continue;
- X if (strncmp(prefix, cp, pflen) == 0)
- X nmatch++;
- X }
- X if (nmatch == 1
- X || (completions = (char **)calloc(nmatch, sizeof(char *))) == NULL) {
- X closedir(dirp);
- X return 0;
- X }
- X mark_str(&str_mark);
- X
- X rewinddir(dirp);
- X for (comp = completions; (dp = readdir(dirp)) != NULL; ) {
- X cp = dp->d_name;
- X if (*cp == '.' && (cp[1] == '\0' || (cp[1] == '.' && cp[2] == '\0')))
- X continue;
- X if (strncmp(prefix, cp, pflen) == 0)
- X strcpy(*comp++ = alloc_str(strlen(cp)), cp);
- X }
- X closedir(dirp);
- X *comp = (char *)0;
- X qsort((char *)completions, comp - completions, sizeof(char *), sort_directory);
- X comp_iterator = completions;
- X comp_help = completions;
- X
- X dir_tail = dir_path;
- X while (*dir_tail++ = *dir++);
- X dir_tail[-1] = '/';
- X
- X return 1;
- X}
- X
- Xstatic next_directory(buffer)
- X register char *buffer;
- X{
- X if (*comp_iterator != NULL) {
- X strcpy(dir_tail, *comp_iterator);
- X strcpy(buffer, *comp_iterator++);
- X
- X if ( file_exist(dir_path, "d") )
- X strcat(buffer, "/");
- X return 1;
- X }
- X close_directory();
- X return 0;
- X}
- X
- Xhelp_directory()
- X{
- X list_completion((char *)NULL);
- X
- X if (*comp_help == NULL) comp_help = completions;
- X while (*comp_help && list_completion(*comp_help))
- X comp_help++;
- X
- X fl;
- X return 1;
- X}
- X
- Xstatic close_directory()
- X{
- X if (completions) {
- X release_str(&str_mark);
- X free((char *)completions);
- X completions = NULL;
- X }
- X}
- X#endif /* HAVE_DIRECTORY */
- X
- Xstatic int cancel_count;
- X
- Xfcancel(ah)
- Xarticle_header *ah;
- X{
- X if (ah->flag & A_CANCEL) {
- X cancel_count--;
- X ah->flag &= ~A_CANCEL;
- X } else {
- X cancel_count++;
- X ah->flag |= A_CANCEL;
- X }
- X}
- X
- Xstatic folder_header()
- X{
- X so_printxy(0, 0, "Folder: %s", current_group->group_name);
- X
- X return 1; /* number of header lines */
- X}
- X
- Xfolder_menu(path)
- Xchar *path;
- X{
- X FILE *folder;
- X register article_header *ap;
- X news_header_buffer dgbuf;
- X char buffer[256];
- X int more, length, re, menu_cmd, was_raw;
- X memory_marker mem_marker;
- X group_header fake_group;
- X int cc_save;
- X
- X fake_group.group_name = path;
- X fake_group.group_flag = G_RC_UPDATED | G_FOLDER | G_READ;
- X init_group(&fake_group);
- X
- X folder = open_file(group_path_name, OPEN_READ);
- X if (folder == NULL) {
- X msg("%s not found", path);
- X return ME_NO_REDRAW;
- X }
- X
- X was_raw = no_raw();
- X s_keyboard = 0;
- X
- X printf("\rReading: %-.65s", path);
- X clrline();
- X
- X current_group = &fake_group;
- X
- X mark_memory(&mem_marker);
- X
- X ap = alloc_art();
- X
- X more = 1;
- X while (more && (more = get_digest_article(folder, dgbuf)) >= 0) {
- X if (s_keyboard) break;
- X
- X ap->a_number = 0;
- X ap->flag = A_FOLDER;
- X
- X ap->lines = digest.dg_lines;
- X
- X ap->hpos = digest.dg_hpos;
- X ap->fpos = digest.dg_fpos;
- X ap->lpos = digest.dg_lpos;
- X
- X if (digest.dg_from) {
- X length = pack_name(buffer, digest.dg_from, NAME_LENGTH);
- X ap->sender = alloc_str(length);
- X strcpy(ap->sender, buffer);
- X } else
- X ap->sender = "";
- X
- X if (digest.dg_subj) {
- X length = pack_subject(buffer, digest.dg_subj, &re, 255);
- X ap->replies = re;
- X ap->subject = alloc_str(length);
- X strcpy(ap->subject, buffer);
- X } else {
- X ap->replies = 0;
- X ap->subject = "";
- X }
- X
- X add_article(ap);
- X ap = alloc_art();
- X }
- X
- X fclose(folder);
- X
- X if (was_raw) raw();
- X
- X if (s_keyboard) {
- X menu_cmd = ME_NO_REDRAW;
- X } else
- X if (n_articles == 0) {
- X msg("Not a folder (no article header)");
- X menu_cmd = ME_NO_REDRAW;
- X } else {
- X strcpy(buffer, path);
- X fake_group.group_name = buffer; /* save for later use */
- X
- X if (n_articles > 1) {
- X clrdisp();
- X prompt_line = 2;
- X if (!dont_sort_folders) sort_articles();
- X }
- X
- X cc_save = cancel_count;
- X cancel_count = 0;
- X
- X reenter_menu:
- X menu_cmd = menu(folder_header);
- X
- X if (cancel_count) {
- X clrdisp();
- X printf("Folder: %s\nFile: %s\n\n", buffer, group_path_name);
- X printf("Remove %d article%s from folder? ",
- X cancel_count, cancel_count == 1 ? "" : "s");
- X fl;
- X
- X switch (yes(1)) {
- X case 1:
- X printf("\n\n");
- X rewrite_folder();
- X break;
- X case 0:
- X break;
- X default:
- X goto reenter_menu;
- X }
- X }
- X cancel_count = cc_save;
- X }
- X
- X release_memory(&mem_marker);
- X
- X return menu_cmd;
- X}
- X
- X
- Xrewrite_folder()
- X{
- X register FILE *src, *dst;
- X char oldfile[FILENAME], *sp;
- X register int c;
- X register long cnt;
- X register article_header *ah, **ahp;
- X register int n;
- X
- X if ((src = fopen(group_path_name, "r")) == NULL) {
- X msg("Cannot open %s", group_path_name);
- X return;
- X }
- X
- X strcpy(oldfile, group_path_name);
- X sp = strrchr(oldfile, '/');
- X if (!sp) goto move_error;
- X strcpy(sp+1, "~OLD~FOLDER~");
- X
- X unlink(oldfile);
- X if (link(group_path_name, oldfile) < 0) goto move_error;
- X if (unlink(group_path_name) < 0) {
- X if (unlink(oldfile) == 0) goto move_error;
- X printf("\n\n%s was linked to %s --- cannot proceed\n",
- X group_path_name, oldfile);
- X sleep(5);
- X return;
- X }
- X
- X if ((dst = fopen(group_path_name, "w")) == NULL) {
- X fclose(src);
- X goto move_back;
- X }
- X
- X unsort_articles(1);
- X
- X printf("Compressing folder..."); fl;
- X
- X for (ahp = articles, n = n_articles; --n >= 0; ahp++) {
- X ah = *ahp;
- X if (ah->flag & A_CANCEL) continue;
- X fseek(src, ah->hpos, 0);
- X cnt = ah->lpos - ah->hpos;
- X while (--cnt >= 0) {
- X if ((c = getc(src)) == EOF) break;
- X putc(c, dst);
- X }
- X putc(NL, dst);
- X }
- X fclose(src);
- X if (ferror(dst)) {
- X fclose(dst);
- X goto move_back;
- X }
- X return;
- X
- Xmove_back:
- X if (link(oldfile, group_path_name) == 0) {
- X unlink(oldfile);
- X printf("Cannot create new file -- Folder restored\n");
- X sleep(2);
- X } else {
- X printf("Cannot create new file\n\nFolder saved in %s\n",
- X oldfile);
- X sleep(10);
- X }
- X return;
- X
- Xmove_error:
- X fclose(src);
- X printf("\n\nCannot move folder %s to %s\n",
- X group_path_name, oldfile);
- X sleep(3);
- X return;
- X}
- NO_NEWS_IS_GOOD_NEWS
- echo "File folder.c is complete"
- chmod 0644 folder.c || echo "restore of folder.c fails"
- set `wc -c folder.c`;Sum=$1
- if test "$Sum" != "11228"
- then echo original size 11228, current size $Sum;fi
- echo "x - extracting global.c (Text)"
- sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > global.c &&
- X#include <signal.h>
- X#include <errno.h>
- X#include <pwd.h>
- X#include "config.h"
- X
- Xexport char *home_directory;
- Xexport char *nn_directory;
- Xexport char news_directory[] = NEWS_DIRECTORY; /* /usr/spool/news */
- Xexport char lib_directory[] = LIB_DIRECTORY; /* /usr/local/lib/nn */
- Xexport char db_directory[] = DB_DIRECTORY; /* /usr/spool/nn */
- X
- Xexport char *temp_file;
- X
- Xexport char *pager = PAGER; /* pg or more */
- X
- Xexport int is_master;
- X
- X/* signal handler interface */
- X
- Xexport int s_hangup = 0; /* hangup signal */
- Xexport int s_keyboard = 0; /* keyboard interrupt */
- Xexport int s_pipe = 0; /* broken pipe */
- Xexport int s_redraw = 0; /* redraw signal (if job control) */
- X
- Xstatic sig_type catch_hangup(n)
- X{
- X signal(n, SIG_IGN);
- X
- X s_hangup++;
- X}
- X
- Xstatic sig_type catch_keyboard(n)
- X{
- X s_keyboard++;
- X
- X#ifdef RESET_SIGNAL_WHEN_CAUGHT
- X signal(n, catch_keyboard);
- X#endif
- X}
- X
- Xstatic sig_type catch_pipe(n)
- X{
- X s_pipe++;
- X
- X#ifdef RESET_SIGNAL_WHEN_CAUGHT
- X signal(n, catch_pipe);
- X#endif
- X}
- X
- X#ifdef HAVE_JOBCONTROL
- Xstatic sig_type catch_redraw(n)
- X{
- X s_redraw++;
- X
- X#ifdef RESET_SIGNAL_WHEN_CAUGHT
- X signal(n, catch_redraw);
- X#endif
- X}
- X#endif
- X
- X
- Xinit_global(who)
- Xint who;
- X{
- X char *env;
- X unsigned short getuid(), getgid();
- X int getpid();
- X
- X is_master = (who == 1);
- X
- X signal(SIGTERM, catch_hangup);
- X signal(SIGHUP, catch_hangup);
- X signal(SIGPIPE, catch_pipe);
- X signal(SIGALRM, SIG_IGN);
- X
- X#ifdef SIGPWR
- X signal(SIGPWR, catch_hangup);
- X#endif
- X
- X user_id = getuid();
- X group_id = getgid();
- X process_id = getpid();
- X
- X if (is_master) {
- X signal(SIGINT, catch_hangup);
- X signal(SIGQUIT, catch_hangup);
- X return;
- X }
- X
- X signal(SIGINT, catch_keyboard);
- X signal(SIGQUIT, catch_keyboard);
- X#ifdef HAVE_JOBCONTROL
- X signal(SIGCONT, catch_redraw);
- X#endif
- X
- X if ((home_directory = getenv("HOME")) == NULL)
- X user_error("No HOME environment variable");
- X
- X nn_directory = mk_file_name(home_directory, ".nn");
- X
- X if (!file_exist(nn_directory, "drwx"))
- X mkdir(nn_directory, 0755); /* should check here */
- X
- X if ((env = getenv("TMPDIR")) == NULL) env = TMP_DIRECTORY;
- X temp_file = mk_file_name(env, "nn.XXXXXX"); /* dies in ANSI C! */
- X mktemp(temp_file);
- X}
- X
- X/*
- X * this is for admin K & W commands and for master -w
- X */
- X
- Xkill_master(sig)
- Xint sig;
- X{
- X FILE *m_pid;
- X int pid, ok;
- X char buf[10];
- X
- X m_pid = open_file(relative(lib_directory, "MPID"), OPEN_READ);
- X if (m_pid == NULL) {
- X errno = ESRCH;
- X return 0;
- X }
- X
- X ok = 0; /* not yet */
- X
- X if (fgets(buf, 10, m_pid) == NULL)
- X printf("MPID file is empty\n");
- X else {
- X pid = atoi(buf);
- X if (pid <= 2)
- X printf("MPID file contains illegal process id: %d\n", pid);
- X else
- X if (kill(pid, sig) != -1) ok++;
- X }
- X
- X fclose(m_pid);
- X
- X return ok;
- X}
- X
- X
- Xmem_check(addr, size, msg)
- Xchar *addr, *msg;
- Xint size;
- X{
- X if (addr == NULL) {
- X if (is_master)
- X sys_error("Cannot allocate %d %s", size, msg);
- X else
- X user_error("Cannot allocate %d %s", size, msg);
- X }
- X}
- X
- XFILE *open_file(name, mode)
- Xchar *name;
- Xint mode;
- X{
- X FILE *f;
- X int fd;
- X
- X if ((mode & DONT_CREATE) && !file_exist(name, (char *)NULL))
- X return NULL;
- X
- X switch (mode & 0x0f) {
- X
- X case OPEN_READ:
- X
- X f = fopen(name, "r");
- X break;
- X
- X case OPEN_UPDATE:
- X
- X/* f = fopen(name, "r+"); -- not reliable on many systems (sigh) */
- X
- X if ((fd = open(name, O_WRONLY)) >= 0) {
- X if ((f = fdopen(fd, "w")) != NULL) return f;
- X close(fd);
- X }
- X
- X /* fall thru */
- X
- X case OPEN_CREATE:
- X
- X f = fopen(name, "w");
- X break;
- X
- X case OPEN_APPEND:
- X
- X f = fopen(name, "a");
- X break;
- X
- X default:
- X
- X sys_error("Illegal mode: open_file(%s, %d)", name, mode);
- X }
- X
- X if (f) {
- X if (mode & OPEN_UNLINK) unlink(name);
- X return f;
- X }
- X
- X if ((mode & MUST_EXIST) == 0) return NULL;
- X
- X if (is_master)
- X sys_error("Cannot open file %s, mode: %d", name, mode);
- X else {
- X log_entry('R', "Client cannot open file %s, mode: %d", name, mode);
- X user_error("Cannot open file %s", name);
- X }
- X
- X return NULL;
- X}
- X
- X
- X
- X
- X/*
- X * relative -- concat directory name and file name
- X */
- X
- Xchar *relative(dir, name)
- Xchar *dir, *name;
- X{
- X static char concat_path[FILENAME];
- X
- X sprintf(concat_path, "%s/%s", dir, name);
- X return concat_path;
- X}
- X
- X
- Xchar *mk_file_name(dir, name)
- Xchar *dir, *name;
- X{
- X char *buf;
- X
- X buf = malloc((unsigned)(strlen(dir) + strlen(name) + 2));
- X mem_check(buf, 1, "file name");
- X sprintf(buf, "%s/%s", dir, name);
- X
- X return buf;
- X}
- X
- X
- Xchar *home_relative(dir)
- Xchar *dir;
- X{
- X if (dir) {
- X if (*dir == '/')
- X return copy_str(dir);
- X else {
- X if (*dir == '~' && *++dir == '/') dir++;
- X return mk_file_name(home_directory, dir);
- X }
- X }
- X return NULL;
- X}
- X
- X
- Xchar *copy_str(str)
- Xchar *str;
- X{
- X char *new;
- X
- X new = malloc((unsigned)(strlen(str) + 1));
- X mem_check(new, 1, "string");
- X if (new) strcpy(new, str);
- X
- X return new;
- X}
- X
- Xtime_t m_time(f)
- XFILE *f;
- X{
- X struct stat st;
- X
- X if (fstat(fileno(f), &st) < 0) return 0;
- X return st.st_mtime;
- X}
- X
- X
- Xtime_t file_exist(name, mode)
- Xchar *name;
- Xchar *mode;
- X{
- X struct stat statb;
- X extern int errno;
- X
- X if (stat(name, &statb)) return 0;
- X
- X if (mode == NULL) return statb.st_mtime;
- X
- X while (*mode) {
- X switch (*mode++) {
- X case 'd':
- X if ((statb.st_mode & S_IFMT) == S_IFDIR) continue;
- X errno = ENOTDIR;
- X return 0;
- X case 'f':
- X if ((statb.st_mode & S_IFMT) == S_IFREG) continue;
- X if ((statb.st_mode & S_IFMT) == 0000000) continue;
- X if ((statb.st_mode & S_IFMT) == S_IFDIR) {
- X errno = EISDIR;
- X return 0;
- X }
- X break;
- X case 'r':
- X if ((statb.st_mode & 0400) && statb.st_uid == user_id) continue;
- X if ((statb.st_mode & 0040) && statb.st_gid == group_id) continue;
- X if ((statb.st_mode & 0004)) continue;
- X break;
- X case 'w':
- X if ((statb.st_mode & 0200) && statb.st_uid == user_id) continue;
- X if ((statb.st_mode & 0020) && statb.st_gid == group_id) continue;
- X if ((statb.st_mode & 0002)) continue;
- X break;
- X case 'x':
- X if ((statb.st_mode & 0100) && statb.st_uid == user_id) continue;
- X if ((statb.st_mode & 0010) && statb.st_gid == group_id) continue;
- X if ((statb.st_mode & 0001)) continue;
- X break;
- X }
- X errno = EACCES;
- X return 0;
- X }
- X
- X /* all modes are ok */
- X return statb.st_mtime;
- X}
- X
- X
- X
- Xprint_version(fmt)
- Xchar *fmt;
- X{
- X extern int Update_Level, Patch_Level;
- X int param;
- X
- X for (; *fmt; fmt++) {
- X
- X if (*fmt == '%') {
- X switch (*++fmt) {
- X case 'R':
- X param = RELEASE;
- X break;
- X case 'V':
- X param = VERSION;
- X break;
- X case 'P':
- X param = Patch_Level;
- X break;
- X case 'U':
- X param = Update_Level;
- X break;
- X default:
- X continue;
- X }
- X printf("%d", param);
- X continue;
- X }
- X putchar(*fmt);
- X }
- X
- X fl;
- X}
- X
- X/*VARARGS*/
- Xlog_entry(va_alist)
- Xva_dcl
- X{
- X int type;
- X va_list ap;
- X
- X va_start(ap);
- X type = va_arg1(int);
- X enter_log(type, va_args2toN);
- X va_end(ap);
- X}
- X
- X#ifdef HAVE_SYSLOG
- X#include <syslog.h>
- X#endif /* HAVE_SYSLOG */
- X
- X/*VARARGS*/
- Xsys_error(va_alist)
- Xva_dcl
- X{
- X va_list ap;
- X
- X va_start(ap);
- X enter_log('E', va_args1toN);
- X va_end(ap);
- X
- X if (is_master) {
- X#ifndef HAVE_SYSLOG
- X FILE *f;
- X
- X f = open_file("/dev/console", OPEN_CREATE);
- X if (f == NULL) nn_exit(8);
- X fprintf(f, "\n\rNNMASTER FATAL ERROR\n\r");
- X fclose(f);
- X#else /* HAVE_SYSLOG */
- X char buf[512];
- X char *fmt;
- X
- X va_start(ap);
- X fmt = va_arg1(char *);
- X vsprintf(buf, fmt, va_args2toN);
- X va_end(ap);
- X
- X openlog("nnmaster", LOG_CONS, LOG_DAEMON);
- X syslog(LOG_ALERT, "%s", buf);
- X closelog();
- X#endif /* HAVE_SYSLOG */
- X }
- X nn_exit(7);
- X}
- X
- X
- Xstatic enter_log(type, va_tail)
- Xchar type;
- Xva_tdcl
- X{
- X FILE *log;
- X char *msg, buf[512], logname[512];
- X
- X msg = va_arg1(char *);
- X vsprintf(buf, msg, va_args2toN);
- X
- X /* cannot use relative: one of the args may be generated by it */
- X sprintf(logname, "%s/Log", lib_directory);
- X
- X log = open_file(logname, OPEN_APPEND);
- X if (log == NULL) return 0;
- X
- X fprintf(log, "%c: %s (%s): %s\n", type,
- X date_time((time_t)0), user_name(), buf);
- X
- X fclose(log);
- X return 1;
- X}
- X
- X
- Xchar *user_name()
- X{
- X static char *user = NULL;
- X struct passwd *pw, *getpwuid();
- X
- X if (is_master) return "M";
- X
- X if (user == NULL) {
- X pw = getpwuid((int)user_id);
- X if (pw == NULL) user = "?";
- X user = copy_str(pw->pw_name);
- X }
- X
- X return user;
- X}
- X
- X
- Xchar *date_time(t)
- Xtime_t t;
- X{
- X char *str;
- X
- X if (t == (time_t)0) time(&t);
- X str = ctime(&t);
- X
- X str[16] = 0;
- X return str+4;
- X}
- X
- X
- X#ifndef HAVE_MKDIR
- X
- Xmkdir(path, mode)
- Xchar *path;
- Xint mode;
- X{
- X char command[FILENAME*2 + 20];
- X
- X sprintf(command, "{ mkdir %s && chmod %o %s ; } > /dev/null 2>&1",
- X path, mode, path);
- X return system(command);
- X}
- X
- X#endif
- NO_NEWS_IS_GOOD_NEWS
- chmod 0644 global.c || echo "restore of global.c fails"
- set `wc -c global.c`;Sum=$1
- if test "$Sum" != "8789"
- then echo original size 8789, current size $Sum;fi
- echo "x - extracting global.h (Text)"
- sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > global.h &&
- X/*
- X * Marks for global/external variables
- X */
- X
- X#define export /* export variable from module */
- X#define import extern /* import variable into module */
- X
- X/*
- X * Various constants and types
- X */
- X
- Xtypedef int32 article_number;
- Xtypedef int16 group_number;
- Xtypedef uint32 time_stamp;
- X
- X/* frequently used characters */
- X
- X#define NUL '\0'
- X#define TAB '\t'
- X#define NL '\n'
- X#define CR '\r'
- X#define BS '\b'
- X#define SP ' '
- X
- X/* misc macros */
- X
- X#define fl fflush(stdout)
- X
- X#ifdef CTRL
- X#undef CTRL
- X#endif
- X#define CTRL(c) (c&037)
- X
- X#ifndef HAVE_STRCHR
- X#define strrchr rindex
- X#define strchr index
- X#endif
- X
- X#ifdef SIGNAL_HANDLERS_ARE_VOID
- Xtypedef void sig_type;
- X#else
- Xtypedef int sig_type;
- X#endif
- X
- X/*
- X * Some systems don't define these in <sys/stat.h>
- X */
- X
- X#ifndef S_IFMT
- X#define S_IFMT 0170000 /* type of file */
- X#define S_IFDIR 0040000 /* directory */
- X#define S_IFREG 0100000 /* regular */
- X#endif
- X
- X#ifndef O_RDONLY
- X#define O_RDONLY 0
- X#define O_WRONLY 1
- X#define O_RDWR 2
- X#endif
- X
- X/* define types of library functions */
- X
- Xchar *malloc(), *calloc();
- Xchar *getenv(), *ctime();
- Xchar *strchr(), *strrchr();
- Xoff_t lseek(), ftell(), tell();
- Xtime_t time();
- Xint atoi();
- Xlong atol();
- X
- X
- X/* define types of own functions */
- X
- Xchar *mk_file_name(), *home_relative();
- Xchar *date_time(), *user_name();
- Xchar *copy_str();
- X
- Xtime_t file_exist(), m_time();
- X
- Xextern FILE *open_file();
- Xchar *relative();
- X
- X#define OPEN_READ 0 /* open for reading */
- X#define OPEN_UPDATE 1 /* open/create for update */
- X#define OPEN_CREATE 2 /* create/truncate for write */
- X#define OPEN_APPEND 3 /* open for append */
- X
- X#define DONT_CREATE 0x40 /* return if file does not exist */
- X#define MUST_EXIST 0x80 /* fatal error if cannot open */
- X#define OPEN_UNLINK 0x100 /* unlink after open (not OPEN_UPDATE) */
- X
- X
- X/*
- X * Other external definitions
- X *
- X * NOTICE: the distinction between pointers and arrays is important
- X * here (they are global variables - not function arguments)
- X */
- X
- Xextern char
- X
- X *home_directory,
- X *nn_directory,
- X
- X news_directory[],
- X lib_directory[],
- X db_directory[],
- X
- X *pager;
- X
- X
- Xextern int
- X
- X s_hangup, /* hangup signal */
- X s_keyboard, /* keyboard signal */
- X s_pipe, /* broken pipe */
- X s_redraw, /* continue signal after stop */
- X
- X#ifdef NNTP
- X use_nntp, /* 1 iff we are using nntp */
- X#endif
- X
- X is_master;
- X
- X
- Xunsigned short /* as they are on most systems... */
- X
- X user_id,
- X group_id;
- X
- Xint
- X
- X process_id;
- X
- Xextern int errno;
- X
- X#include "vararg.h"
- X#include "data.h"
- X
- X/*
- X * db external data
- X */
- X
- Xextern master_header master;
- X
- X/* group headers */
- X
- Xextern group_header *active_groups, **sorted_groups;
- X
- X/* current group information */
- X
- Xextern char group_path_name[];
- Xextern char *group_file_name;
- X
- Xextern group_header *current_group, *group_sequence;
- X
- Xextern group_header *lookup();
- X
- X
- X#define Loop_Groups_Number(num) \
- X for (num = master.number_of_groups; --num >= 0; )
- X
- X#define Loop_Groups_Header(gh) \
- X for (gh=active_groups+master.number_of_groups; --gh >= active_groups;)
- X
- Xint l_g_index;
- X
- X#define Loop_Groups_Sorted(gh) \
- X for (l_g_index = 0; \
- X (l_g_index < master.number_of_groups) && \
- X (gh = sorted_groups[l_g_index]) ;\
- X l_g_index++)
- X
- X#define Loop_Groups_Sequence(gh) \
- X for (gh = group_sequence; gh; gh = gh->next_group)
- NO_NEWS_IS_GOOD_NEWS
- chmod 0644 global.h || echo "restore of global.h fails"
- set `wc -c global.h`;Sum=$1
- if test "$Sum" != "3245"
- then echo original size 3245, current size $Sum;fi
- echo "x - extracting group.c (Text)"
- sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > group.c &&
- X/*
- X * group menu
- X */
- X
- X#include "config.h"
- X#include "articles.h"
- X#include "db.h"
- X#include "term.h"
- X#include "menu.h"
- X#include "keymap.h"
- X#include "regexp.h"
- X
- X
- Xexport int dont_split_digests = 0;
- Xexport int dont_sort_articles = 0;
- X
- Ximport int article_limit, also_read_articles;
- Ximport int no_update;
- Ximport int merged_menu;
- X
- Xchar *quick_match();
- X
- X/*
- X * completion of group name
- X */
- X
- Xgroup_completion(hbuf, ix)
- Xchar *hbuf;
- Xint ix;
- X{
- X static group_number next_group, n1, n2;
- X static char *head, *tail, *last;
- X static int tail_offset, prev_lgt, l1, l2;
- X static group_header *prev_group, *p1, *p2;
- X register group_header *gh;
- X register char *t1, *t2;
- X int order;
- X
- X if (ix < 0) return 0;
- X
- X if (hbuf) {
- X n2 = next_group = 0;
- X p2 = prev_group = NULL;
- X l2 = 0;
- X
- X if (head = strrchr(hbuf, ','))
- X head++;
- X else
- X head = hbuf;
- X tail = hbuf + ix;
- X tail_offset = ix - (head - hbuf);
- X if (last = strrchr(head, '.')) last++; else last = head;
- X return 1;
- X }
- X
- X if (ix) {
- X n1 = next_group, p1 = prev_group, l1 = prev_lgt;
- X next_group = n2, prev_group = p2, prev_lgt = l2;
- X list_completion((char *)NULL);
- X }
- X
- X *tail = NUL;
- X
- X while (next_group < master.number_of_groups) {
- X gh = sorted_groups[next_group++];
- X if (gh->group_name_length <= tail_offset) continue;
- X
- X if (prev_group &&
- X strncmp(prev_group->group_name, gh->group_name, prev_lgt) == 0)
- X continue;
- X
- X order = strncmp(gh->group_name, head, tail_offset);
- X if (order < 0) continue;
- X if (order > 0) break;
- X
- X t1 = gh->group_name + tail_offset;
- X if (t2 = strchr(t1, '.')) {
- X strncpy(tail, t1, t2 - t1 + 1);
- X tail[t2 - t1 + 1] = NUL;
- X } else
- X strcpy(tail, t1);
- X
- X prev_group = gh;
- X prev_lgt = tail_offset + strlen(tail);
- X if (ix) {
- X if (list_completion(last) == 0) break;
- X } else
- X return 1;
- X }
- X
- X if (ix) {
- X n2 = next_group, p2 = prev_group, l2 = prev_lgt;
- X if (n2 > master.number_of_groups)
- X n2 = 0, p2 = NULL, l2 = 0;
- X next_group = n1, prev_group = p1, prev_lgt = l1;
- X return 1;
- X }
- X
- X next_group = 0;
- X prev_group = NULL;
- X return 0;
- X}
- X
- X
- X/* flags to access_group */
- X
- X#define ALSO_CROSS_POSTINGS 0x01
- X#define DONT_SORT_ARTICLES 0x02
- X#define DONT_SPLIT_DIGESTS 0x04 /* only full digest */
- X#define ALSO_FULL_DIGEST 0x08 /* also full digest */
- X
- Xstatic access_group(gh, first_article, last_article, flags, submask, do_kill)
- Xregister group_header *gh;
- Xarticle_number first_article, last_article;
- Xint flags;
- Xchar *submask;
- Xint do_kill;
- X{
- X FILE *data;
- X data_header hdr;
- X off_t data_offset;
- X register article_header *ah;
- X cross_post_number cross_post;
- X int skip_digest;
- X int n;
- X string_marker str_marker;
- X memory_marker mem_marker;
- X article_number art_num;
- X static regexp *subpattern = NULL;
- X static char subptext[80];
- X
- X if (init_group(gh) <= 0) return -2;
- X
- X if (first_article < gh->first_l_article)
- X first_article = gh->first_l_article;
- X
- X if (last_article > gh->last_l_article)
- X last_article = gh->last_l_article;
- X
- X if (last_article == 0 || first_article > last_article) return 0;
- X
- X data = open_data_file(gh, 'd', OPEN_READ);
- X if (data == NULL) return -1;
- X
- X if ((data_offset = get_data_offset(gh, first_article)) == (off_t)(-1))
- X return -1;
- X
- X if (submask && *submask == '/') {
- X submask++;
- X if (subpattern != NULL) {
- X if (strncmp(submask, subptext, 80) != 0) {
- X free(subpattern);
- X subpattern = NULL;
- X }
- X }
- X if (subpattern == NULL) {
- X strncpy(subptext, submask, 80);
- X subpattern = regcomp(submask);
- X if (subpattern == NULL) return -1;
- X }
- X submask = NULL;
- X } else
- X if (subpattern != NULL) {
- X free(subpattern);
- X subpattern = NULL;
- X }
- X
- X mark_memory(&mem_marker);
- X
- X ah = alloc_art();
- X
- X skip_digest = 0;
- X
- Xskip_to_next:
- X fseek(data, data_offset, 0);
- X
- Xread_next:
- X if (data_offset >= gh->data_write_offset) goto out;
- X
- X if (!db_read_art(data, &hdr, &data_offset)) goto out;
- X
- X if (hdr.dh_lpos == (off_t)0) /* article not accessible */
- X goto read_next;
- X
- X if (art_num = hdr.dh_number) {
- X if (art_num < 0) art_num = -art_num;
- X if (art_num > gh->last_l_article ||
- X art_num < gh->first_l_article)
- X goto data_error;
- X }
- X
- X data_offset += hdr.dh_cross_postings * sizeof(cross_post_number)
- X + hdr.dh_sender_length
- X + hdr.dh_subject_length;
- X
- X if (skip_digest && IS_SUB_DIGEST(hdr)) goto skip_to_next;
- X
- X skip_digest = 0;
- X
- X if (hdr.dh_cross_postings) {
- X if ((flags & ALSO_CROSS_POSTINGS) == 0) {
- X n = hdr.dh_cross_postings;
- X do {
- X if (fread((char *)&cross_post, sizeof(cross_post_number), 1, data) != 1)
- X goto data_error;
- X#ifdef NETWORK_DATABASE
- X#ifndef NETWORK_BYTE_ORDER
- X cross_post = ntohl(cross_post);
- X#endif
- X#endif
- X if (active_groups[cross_post].group_flag & G_SUBSCRIPTION)
- X break;
- X } while (--n > 0);
- X if (n > 0) {
- X if (IS_DIGEST_HEADER(hdr)) skip_digest++;
- X goto skip_to_next;
- X }
- X } else
- X fseek(data, (off_t)(sizeof(cross_post_number)*hdr.dh_cross_postings), 1);
- X }
- X
- X ah->flag = 0;
- X
- X if (IS_DIGEST_HEADER(hdr)) {
- X if ((flags & (DONT_SPLIT_DIGESTS | ALSO_FULL_DIGEST)) == 0)
- X goto skip_to_next; /* don't want the full digest when split */
- X skip_digest++;
- X ah->flag |= A_FULL_DIGEST;
- X } else
- X if (IS_SUB_DIGEST(hdr))
- X ah->flag |= A_DIGEST;
- X
- X ah->a_number = ARTICLE_NUMBER(hdr);
- X if (ah->a_number > last_article) goto out;
- X
- X mark_str(&str_marker);
- X
- X if (hdr.dh_sender_length) {
- X ah->sender = alloc_str((int)hdr.dh_sender_length);
- X if (fread(ah->sender, sizeof(char), (int)hdr.dh_sender_length, data)
- X != hdr.dh_sender_length) goto data_error;
- X } else
- X ah->sender = "";
- X
- X if (hdr.dh_subject_length) {
- X ah->subject = alloc_str((int)hdr.dh_subject_length);
- X if (fread(ah->subject, sizeof(char), (int)hdr.dh_subject_length, data)
- X != hdr.dh_subject_length) goto data_error;
- X } else
- X ah->subject = "";
- X
- X ah->hpos = hdr.dh_hpos;
- X ah->fpos = ah->hpos + (off_t)(hdr.dh_fpos);
- X ah->lpos = hdr.dh_lpos;
- X
- X ah->replies = hdr.dh_replies;
- X ah->lines = hdr.dh_lines;
- X
- X ah->t_stamp = hdr.dh_date;
- X
- X if ((subpattern && !regexec(subpattern, ah->subject)) ||
- X (submask && quick_match(ah->subject, submask) == NULL) ||
- X (do_kill && kill_article(ah))) {
- X killed_articles++;
- X release_str(&str_marker);
- X goto read_next;
- X }
- X
- X ah->a_group = merged_menu ? current_group : NULL;
- X
- X add_article(ah);
- X ah = alloc_art();
- X
- X goto read_next;
- X
- X
- Xdata_error:
- X log_entry('E', "%s: data inconsistency", gh->group_name);
- X fclose(data);
- X release_memory(&mem_marker);
- X return -1;
- X
- Xout:
- X fclose(data);
- X
- X if ((flags & DONT_SORT_ARTICLES) == 0)
- X sort_articles();
- X
- X return n_articles;
- X}
- X
- Xstatic article_number current_first_article;
- X
- X
- Xstatic print_header()
- X{
- X extern long unread_articles;
- X extern int unread_groups;
- X
- X so_printxy(0, 0, "Newsgroup: %s", current_group->group_name);
- X clrline();
- X
- X so_gotoxy(-1, 0, 0);
- X
- X so_printf("Articles: %d", n_articles);
- X
- X if (no_update) {
- X so_printf(" NO UPDATE");
- X } else {
- X if (current_first_article > current_group->first_article + 1)
- X so_printf((killed_articles > 0) ? "(L-%ld,K-%d)" : "(L-%ld)",
- X current_first_article - current_group->first_article - 1,
- X killed_articles);
- X else
- X if (killed_articles > 0)
- X so_printf(" (K-%d)", killed_articles);
- X
- X if (unread_articles > 0) {
- X so_printf(" of %ld", unread_articles);
- X if (unread_groups > 0)
- X so_printf("/%d", unread_groups);
- X }
- X
- X if ((current_group->group_flag & G_SUBSCRIPTION) == 0)
- X so_printf(" UNSUB");
- X else if (current_group->group_flag & G_NEW)
- X so_printf(" NEW");
- X
- X if (current_group->group_flag & G_READ)
- X so_printf(" READ");
- X }
- X
- X so_end();
- X
- X return 1; /* number of lines in header */
- X}
- X
- X
- X
- Xgroup_menu(gh, first_art, submask, do_kill, menu)
- Xregister group_header *gh;
- Xarticle_number first_art;
- Xchar *submask;
- Xint do_kill;
- Xint (*menu)();
- X{
- X int status, was_unread;
- X int menu_cmd, access_mode, did_selection, o_killed;
- X article_number o_first_article, prev_last, last_article;
- X memory_marker sel_marker; /* for marking old selection */
- X
- X#define menu_return(cmd) { menu_cmd = (cmd); goto menu_exit; }
- X
- X o_first_article = current_first_article;
- X o_killed = killed_articles;
- X mark_memory(&sel_marker);
- X
- Xafter_selection:
- X
- X did_selection = 0;
- X killed_articles = 0;
- X
- X prev_last = gh->last_l_article;
- X
- X was_unread = add_unread(gh, -1);
- X
- X if (update_group(gh) < 0) {
- X status = -2;
- X goto access_exception;
- X }
- X
- X if (gh->last_l_article < prev_last) {
- X /* expire + renumbering */
- X int32 updflag;
- X
- X if ((gh->last_article = gh->first_l_article - 1) < 0)
- X gh->last_article = 0;
- X gh->first_article = gh->last_article;
- X updflag = gh->group_flag & (G_RC_UPDATED|G_READ);
- X gh->group_flag &= ~(G_RC_UPDATED|G_READ);
- X update_rc(gh);
- X gh->group_flag &= ~(G_RC_UPDATED|G_READ);
- X gh->group_flag |= updflag;
- X }
- X
- X if (was_unread)
- X add_unread(gh, 1);
- X
- X gotoxy(0, 0);
- X fl;
- X
- X access_mode = 0;
- X if (also_read_articles || submask)
- X access_mode |= ALSO_CROSS_POSTINGS;
- X if (dont_split_digests)
- X access_mode |= DONT_SPLIT_DIGESTS;
- X if (dont_sort_articles)
- X access_mode |= DONT_SORT_ARTICLES;
- X
- X if (first_art == -1) {
- X if (submask == NULL && !also_read_articles) {
- X if (has_selection(gh, ¤t_first_article, &last_article)) {
- X status = access_group(gh, current_first_article, last_article,
- X DONT_SORT_ARTICLES, (char *)NULL, do_kill);
- X do_selections(status >= 0 && n_articles);
- X if (status < 0) goto access_exception;
- X if (n_articles) {
- X did_selection = 1;
- X if (!dont_sort_articles) sort_articles();
- X goto read_the_articles;
- X }
- X }
- X }
- X
- X if (also_read_articles || submask)
- X current_first_article = gh->first_l_article;
- X else
- X current_first_article = gh->last_article + 1;
- X
- X if (article_limit > 0) {
- X article_number temp;
- X
- X temp = gh->last_l_article - article_limit + 1;
- X if (current_first_article < temp) current_first_article = temp;
- X }
- X } else
- X current_first_article = first_art;
- X
- X status = access_group(gh, current_first_article, gh->last_l_article,
- X access_mode, submask, do_kill);
- X
- X access_exception:
- X
- X if (status < 0) {
- X if (status == -1)
- X msg("DATABASE CORRUPTED FOR GROUP %s", gh->group_name);
- X/* else
- X msg("Group %s is blocked - try again later", gh->group_name);
- X*/
- X menu_return( ME_NEXT );
- X }
- X
- X if (n_articles == 0)
- X menu_return( ME_NO_ARTICLES );
- X
- X read_the_articles:
- X
- X menu_cmd = (*menu)(print_header);
- X
- X menu_exit:
- X
- X if (menu_cmd == ME_QUIT || menu_cmd == ME_NEXT || menu_cmd == ME_PREV)
- X if (submask == NULL && !no_update)
- X save_selection(gh, current_first_article, gh->last_l_article);
- X
- X if (menu_cmd == ME_READ || menu_cmd == ME_NO_ARTICLES) {
- X if (did_selection) {
- X int was_read = gh->group_flag & (G_READ|G_RC_UPDATED);
- X
- X prev_last = gh->last_l_article;
- X gh->last_l_article = last_article;
- X update_rc(gh);
- X gh->last_l_article = prev_last;
- X
- X if (last_article < gh->last_l_article) {
- X gh->group_flag &= ~ (G_READ|G_RC_UPDATED);
- X gh->group_flag |= was_read;
- X release_memory(&sel_marker);
- X goto after_selection;
- X }
- X } else
- X if (submask == NULL && !also_read_articles &&
- X (menu_cmd != ME_NO_ARTICLES ||
- X (gh->group_flag & G_NEW) == 0) &&
- X (first_art == -1 ||
- X current_first_article == gh->first_article + 1))
- X update_rc(gh);
- X }
- X
- X current_first_article = o_first_article;
- X killed_articles = o_killed;
- X
- X return menu_cmd;
- X}
- X
- X
- Xgoto_group(command, ah)
- Xint command;
- Xarticle_header *ah;
- X{
- X register group_header *gh;
- X char ans1, *answer, *submask, buffer[FILENAME];
- X article_number first, o_current_first;
- X memory_marker mem_marker;
- X group_header *orig_group;
- X int menu_cmd;
- X extern int menu(), file_completion();
- X extern article_header *get_menu_article();
- X extern int get_from_macro;
- X extern group_header *jump_to_group;
- X
- X#define goto_return( cmd ) \
- X { menu_cmd = cmd; goto goto_exit; }
- X
- X m_startinput();
- X
- X gh = orig_group = current_group;
- X
- X o_current_first = current_first_article;
- X
- X submask = NULL;
- X
- X if (command == K_GOTO_GROUP)
- X goto get_group_name;
- X
- X for (;;) {
- X if (command == K_ADVANCE_GROUP)
- X gh = gh->next_group;
- X else
- X gh = gh->prev_group;
- X
- X if (gh == NULL)
- X goto_return(ME_NO_REDRAW);
- X
- X if (gh->first_l_article >= gh->last_l_article) continue;
- X
- X prompt("\1Enter\1 %s%s%s ?", gh->group_name,
- X gh->group_flag & G_SUBSCRIPTION ? "" : " (UNSUB)",
- X gh->group_flag & G_READ ? " (READ)" : "" );
- X
- X command = get_c();
- X if (command & GETC_COMMAND) goto_return(ME_REDRAW);
- X if (command == 'y' || command == 'Y') break;
- X if (command == 'n' || command == 'N') goto_return(ME_NO_REDRAW);
- X
- X command = menu_key_map[command];
- X if (command == K_CONTINUE) break;
- X if (command == K_ADVANCE_GROUP) continue;
- X if (command == K_BACK_GROUP) continue;
- X if (command == K_GOTO_GROUP) goto get_group_name;
- X goto_return(ME_NO_REDRAW);
- X }
- X
- X if (gh == orig_group) goto_return(ME_NO_REDRAW);
- X
- X goto get_first;
- X
- X get_group_name:
- X
- X if (current_group == NULL) {
- X prompt("\1Enter Group or Folder\1 (+./~) ");
- X answer = get_s(NONE, NONE, "+./~", group_completion);
- X } else {
- X prompt("\1Group or Folder\1 (+./~ %=N) ");
- X answer = get_s(NONE, NONE, "+./0123456789~=%", group_completion);
- X }
- X
- X if (answer == NULL) goto_return(ME_NO_REDRAW);
- X
- X if ((ans1 = *answer) == NUL) {
- X if (current_group == NULL) goto_return(ME_NO_REDRAW);
- X goto get_first;
- X }
- X
- X sprintf(buffer, "%c", ans1);
- X
- X switch (ans1) {
- X
- X case '%':
- X if (current_group == NULL) goto_return(ME_NO_REDRAW);
- X if ((current_group->group_flag & G_FOLDER) == 0) {
- X if (!ah) {
- X prompt("\1READ\1");
- X if ((ah = get_menu_article()) == NULL)
- X goto_return(ME_NO_REDRAW);
- X }
- X if ((ah->flag & A_DIGEST) == 0) {
- X *group_file_name = NUL;
- X sprintf(buffer, "%s%ld", group_path_name, ah->a_number);
- X answer = buffer;
- X goto get_folder;
- X }
- X }
- X
- X msg("cannot split articles inside a folder or digest");
- X goto_return(ME_NO_REDRAW);
- X
- X case '.':
- X case '~':
- X strcat(buffer, "/");
- X case '+':
- X case '/':
- X if (!get_from_macro) {
- X prompt("\1Folder\1 ");
- X answer = get_s(NONE, buffer, NONE, file_completion);
- X if (answer == NULL || answer[0] == NUL) goto_return(ME_NO_REDRAW);
- X }
- X
- X get_folder:
- X m_endinput();
- X if (!expand_file_name(buffer, answer)) goto_return (ME_NO_REDRAW);
- X menu_cmd = folder_menu(buffer);
- X init_group(orig_group);
- X goto goto_exit;
- X
- X
- X case 'a':
- X if (answer[1] == NUL || strcmp(answer, "all") == 0) {
- X if (current_group == NULL) goto_return(ME_NO_REDRAW);
- X first = 0;
- X goto more_articles;
- X }
- X break;
- X
- X case 'u':
- X if (answer[1] == NUL || strcmp(answer, "unread") == 0) {
- X if (current_group == NULL) goto_return(ME_NO_REDRAW);
- X first = gh->first_article + 1;
- X goto more_articles;
- X }
- X break;
- X
- X case 's':
- X if (answer[1] == NUL) {
- X if (current_group == NULL) goto_return(ME_NO_REDRAW);
- X goto get_subject;
- X }
- X
- X break;
- X
- X case '=':
- X if (current_group == NULL) goto_return(ME_NO_REDRAW);
- X goto get_subject;
- X
- X case '0':
- X case '1':
- X case '2':
- X case '3':
- X case '4':
- X case '5':
- X case '6':
- X case '7':
- X case '8':
- X case '9':
- X if (current_group == NULL) goto_return(ME_NO_REDRAW);
- X if (current_first_article <= gh->first_l_article) {
- X msg("No extra articles");
- X flush_input();
- X goto_return(ME_NO_REDRAW);
- X }
- X
- X if (!get_from_macro) {
- X prompt("\1Number of extra articles\1 max %ld: ",
- X current_first_article - gh->first_l_article);
- X sprintf(buffer, "%c", ans1);
- X answer = get_s(NONE, buffer, NONE, NO_COMPLETION);
- X if (answer == NULL || *answer == NUL) goto_return(ME_NO_REDRAW);
- X }
- X
- X first = current_first_article - atol(answer);
- X goto more_articles;
- X
- X default:
- X break;
- X }
- X
- X if ((gh = lookup(answer)) == NULL) {
- X msg("No group named %s", answer);
- X goto_return(ME_NO_REDRAW);
- X }
- X
- X
- X get_first:
- X
- X m_advinput();
- X
- X if (gh->last_l_article == 0 ||
- X gh->last_l_article < gh->first_l_article) {
- X msg("Group %s is empty", answer);
- X goto_return(ME_NO_REDRAW);
- X }
- X
- X if (gh == orig_group
- X && current_first_article <= gh->first_article) {
- X
- X if (current_first_article <= gh->first_l_article) {
- X /* no more articles to read */
- X *answer = '=';
- X get_from_macro = 0;
- X goto get_subject;
- X }
- X
- X prompt("\1Number of extra articles\1 all %ld, =subject: ",
- X (long)(current_first_article - gh->first_l_article));
- X
- X answer = "a=s";
- X } else {
- X if (gh != orig_group)
- X current_first_article = gh->last_l_article + 1;
- X
- X prompt("\1Number of%s articles\1 u)nread %ld,%s a)ll %ld, s)ubject: ",
- X gh == orig_group ? " extra" : "",
- X (long)(current_first_article - gh->first_article - 1),
- X (gh->group_flag & G_UNREAD_COUNT) ? " j)ump," : "",
- X (long)(current_first_article - gh->first_l_article));
- X
- X answer = (gh->group_flag & G_UNREAD_COUNT) ? "uja=s" : "ua=s";
- X }
- X
- X answer = get_s(NONE, NONE, answer, NO_COMPLETION);
- X if (answer == NULL) goto_return(ME_NO_REDRAW);
- X
- Xget_subject: /* when *answer == '=' */
- X
- X switch (*answer) {
- X
- X case NUL:
- X if (gh != orig_group || current_first_article <= gh->first_l_article) {
- X first = 0;
- X break;
- X }
- X /* else fall thru */
- X
- X case 'u':
- X first = gh->first_article + 1;
- X break;
- X
- X case 'j':
- X jump_to_group = gh;
- X goto_return(ME_QUIT);
- X
- X case 'a':
- X first = 0;
- X break;
- X
- X case 's':
- X case '=':
- X first = 0;
- X if (get_from_macro) {
- X submask = answer + 1;
- X } else {
- X prompt("=");
- X submask = get_s(ah ? ah->subject : NONE, NONE, ah ? NONE : "%=",
- X NO_COMPLETION);
- X if (submask == NULL) goto_return(ME_NO_REDRAW);
- X if (*submask == '%' || *submask == '=') {
- X if ((ah = get_menu_article()) == 0) goto_return(ME_NO_REDRAW);
- X *submask = NUL;
- X }
- X }
- X
- X if (*submask == NUL)
- X if (ah) {
- X strncpy(submask, ah->subject, GET_S_BUFFER);
- X submask[GET_S_BUFFER-1] = NUL;
- X } else
- X goto_return(ME_NO_REDRAW);
- X
- X if (*submask) {
- X if (*submask != '/') init_quick_match(submask);
- X } else
- X submask = NULL;
- X break;
- X
- X case '0':
- X case '1':
- X case '2':
- X case '3':
- X case '4':
- X case '5':
- X case '6':
- X case '7':
- X case '8':
- X case '9':
- X first = current_first_article - atol(answer);
- X break;
- X
- X default:
- X ding();
- X goto_return(ME_NO_REDRAW);
- X }
- X
- X if (first > gh->last_l_article) goto_return(ME_NO_REDRAW);
- X
- Xmore_articles:
- X if (gh == orig_group && submask == NULL &&
- X first < current_first_article) {
- X if (current_first_article <= gh->first_l_article) {
- X msg("No extra articles");
- X goto_return(ME_NO_REDRAW);
- X }
- X
- X if (access_group(gh, first, current_first_article - 1,
- X ALSO_CROSS_POSTINGS, (char *)NULL, 0) < 0) {
- X msg("Cannot read extra articles (now)");
- X goto_return(ME_NO_REDRAW);
- X }
- X
- X current_first_article = first;
- X
- X goto_return(ME_REDRAW);
- X }
- X
- X mark_memory(&mem_marker);
- X m_endinput();
- X menu_cmd = group_menu(gh, first, submask, 0, menu);
- X release_memory(&mem_marker);
- X
- X if (gh != orig_group) {
- X current_first_article = o_current_first;
- X if (orig_group) init_group(orig_group);
- X }
- X
- Xgoto_exit:
- X m_endinput();
- X return menu_cmd;
- X}
- X
- Xstatic merged_header()
- X{
- X so_printxy(0, 0, "MERGED NEWS GROUPS: %d ARTICLES", n_articles);
- X clrline();
- X
- X return 1;
- X}
- X
- Xmerge_and_read(submask, do_kill)
- Xchar *submask;
- Xint do_kill;
- X{
- X register group_header *cur;
- X group_header dummy_group;
- X int access_mode;
- X
- X free_memory();
- X
- X access_mode = DONT_SORT_ARTICLES;
- X if (also_read_articles || submask)
- X access_mode |= ALSO_CROSS_POSTINGS;
- X if (dont_split_digests)
- X access_mode |= DONT_SPLIT_DIGESTS;
- X
- X for (cur = group_sequence; cur != NULL; cur = cur->next_group) {
- X if (s_hangup || s_keyboard) break;
- X
- X if (cur->group_flag & G_FOLDER) {
- X printf("\n\rIgnoring folder: %s\n\r", cur->group_name);
- X continue;
- X }
- X
- X if (!also_read_articles)
- X if (cur->last_article >= cur->last_l_article)
- X continue;
- X
- X printf("\r%s", cur->group_name); clrline();
- X
- X access_group(cur, -1, cur->last_l_article, access_mode, submask, do_kill);
- X }
- X merge_memory();
- X if (n_articles == 0) return;
- X if (!dont_sort_articles) sort_articles();
- X
- X dummy_group.group_flag = 0;
- X dummy_group.save_file = NULL;
- X dummy_group.group_name = "dummy";
- X dummy_group.kill_list = NULL;
- X
- X current_group = &dummy_group;
- X
- X menu(merged_header);
- X
- X free_memory();
- X}
- X
- Xunsubscribe(gh)
- Xgroup_header *gh;
- X{
- X if (no_update) {
- X msg("nn started in \"no update\" mode");
- X return 0;
- X }
- X
- X if (gh->group_flag & G_FOLDER) {
- X msg("cannot unsubscribe to a folder");
- X return 0;
- X }
- X
- X if (gh->group_flag & G_SUBSCRIPTION) {
- X prompt("\1Unsubscribe to\1 %s ? ", gh->group_name);
- X if (yes(0) <= 0) return 0;
- X
- X add_unread(gh, -1);
- X gh->group_flag &= ~G_SUBSCRIPTION;
- X write_rc_entry(gh, 0);
- X return 1;
- X }
- X
- X prompt("Already unsubscribed. \1Resubscribe to\1 %s ? ",
- X gh->group_name);
- X if (yes(1) <= 0) return 0;
- X
- X gh->group_flag |= G_SUBSCRIPTION;
- X write_rc_entry(gh, 0);
- X
- X add_unread(gh, 1);
- X
- X return 1;
- X}
- X
- X
- Xgroup_overview(amount)
- Xint amount; /* 0=>unread,subscribed, 1=>unread,all, 2=>all,all 3=>unsub*/
- X{
- X register group_header *gh;
- X
- X clrdisp();
- X
- X pg_init(0, 2);
- X
- X Loop_Groups_Sorted(gh) {
- X
- X if (gh->group_flag & G_NO_DIRECTORY) continue;
- X
- X if (amount <= 1 && gh->last_article >= gh->last_l_article)
- X continue;
- X
- X if (amount == 0 && (gh->group_flag & G_SUBSCRIPTION) == 0)
- X continue;
- X
- X if (amount == 3 && (gh->group_flag & G_SUBSCRIPTION))
- X continue;
- X
- X if (pg_next() < 0) break;
- X
- X printf("%6ld %s%s",
- X (long)(gh->last_l_article - gh->last_article),
- X gh->group_name,
- X gh->group_flag & G_SUBSCRIPTION ? "" : " (!)");
- X }
- X
- X pg_end();
- X}
- NO_NEWS_IS_GOOD_NEWS
- chmod 0644 group.c || echo "restore of group.c fails"
- set `wc -c group.c`;Sum=$1
- if test "$Sum" != "22057"
- then echo original size 22057, current size $Sum;fi
- echo "x - extracting help.commands (Text)"
- sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > help.commands &&
- X;:ACOMMAND NAMES;:A ;:AMAP COMMAND;:A
- X
- X;:BNAME MENU MORE FUNCTION
- Xadvance-group A advance one group in sequence
- Xback-group B go back one group in sequence
- Xcancel C C cancel an article
- Xcommand : : extenced command prefix
- Xcompress c compress text (eliminate extra spaces)
- Xcontinue SPACE SPACE the "space bar" command
- Xfind / regular expression search
- Xfind-next . repeat regular expression search
- Xfollow F f F follow up
- Xfull-digest H show complete digest
- Xgoto-group G G goto group or open folder
- Xgoto-menu = go back to menu
- Xhelp ? ? online help
- Xkill-select K K kill/select handling
- Xlayout L change menu layout
- Xline+1 down CR next menu line/scroll one line
- Xline-1 up previous menu line
- Xline=@ g goto specific line
- Xmail M m M mail or forward
- Xmessage ^P ^P repeat last prompt line message
- Xnext-article n skip to next article
- Xnext-group N goto to next group without reading current
- Xnext-subject k skip to next article with different subject
- Xnil unbound key
- Xoverview Y Y show groups with unread news
- Xpage+1 > goto next page if any
- Xpage+1/2 d ^D scroll half page forward
- Xpage-1 < DEL goto one page back
- Xpage-1/2 u ^U scroll half page backwards
- Xpage=$ $ $ goto end of menu/article
- Xpage=0 h goto header of article
- Xpage=1 ^ ^ goto first menu/article page
- Xpage=@ goto specific page of article (not implemented)
- Xpost post new article
- Xpreview % preview article
- Xprevious P P goto previous group/article
- Xprint p print article
- Xquit Q Q quit nn
- Xread-return Z read selected articles and return to menu
- Xread-skip X read selected article, skip unseen menu pages
- Xredraw ^L ^R ^L ^R redraw screen
- Xreply R r R reply
- Xrot13 D decrypt rot13 article
- Xsave-body W w W save article without header
- Xsave-full S s S save article with full header
- Xsave-short O o O save article with short header
- Xselect . select (or deselect) current menu entry
- Xselect-auto + select "auto-selected" articles
- Xselect-invert @ invert all selections on current menu page
- Xselect-range - select range of articles
- Xselect-subject * select all articles with current subject
- Xshell ! ! shell command prefix
- Xunselect-all ~ unselect all articles
- Xunshar unshar article(s)
- Xunsub U U unsubscribe (or subscribe) to current group
- Xversion V V print release information
- NO_NEWS_IS_GOOD_NEWS
- chmod 0644 help.commands || echo "restore of help.commands fails"
- set `wc -c help.commands`;Sum=$1
- if test "$Sum" != "2312"
- then echo original size 2312, current size $Sum;fi
- echo "x - extracting help.extended (Text)"
- sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > help.extended &&
- X;:AEXTENDED COMMANDS;:A
- X
- X:help COMMAND give help on specific command
- X
- X:q! quit nn without update (only with -B option)
- X:x quit nn, mark current group as read
- X
- X:mkdir [DIR] create directory DIR (will prompt for DIR if omitted)
- X:cd [DIR] change working directory to DIR
- X
- X:admin enter administration mode
- X
- X:set OPTION [VALUE] set or unset option (use 'help set' for more info)
- X:map MODE KEY COMMAND remap key or command
- X:show TABLE show contents of various tables
- X:sort MODE sort menu according to subject, age, or arrival
- X
- X:unread (N) mark current group as unread (last N articles)
- X:coredump abort with a core dump
- NO_NEWS_IS_GOOD_NEWS
- chmod 0644 help.extended || echo "restore of help.extended fails"
- set `wc -c help.extended`;Sum=$1
- if test "$Sum" != "626"
- then echo original size 626, current size $Sum;fi
- echo "x - extracting help.help (Text)"
- sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > help.help &&
- X;:AHELP COMMAND;:A
- X
- XSynopsis
- X
- X :help subject
- X
- XHelp is available on the the following subjects:
- X
- Xcommands commands that can be bound to keys
- Xextended extended commands (:command)
- Xmap key mapping
- Xset variable setting
- NO_NEWS_IS_GOOD_NEWS
- echo "End of part 4"
- echo "File help.help is continued in part 5"
- echo "5" > s2_seq_.tmp
- exit 0
- ---
- Kim F. Storm storm@texas.dk Tel +45 429 174 00
- Texas Instruments, Marielundvej 46E, DK-2730 Herlev, Denmark
- No news is good news, but nn is better!
-
-