Tass newsreader (part 2 of 2)
Rich Skrenta
skrenta at blekko.commodore.com
Fri Feb 15 06:35:43 AEST 1991
# This is a shell archive. Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# This archive contains:
# page.c prompt.c screen.c select.c
# tass.h time.c
#
echo x - page.c
cat >page.c <<'@EOF'
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "tass.h"
#define MAX_PAGES 1000
#define NOTE_UNAVAIL -1
char note_h_path[LEN]; /* Path: */
char note_h_date[LEN]; /* Date: */
char note_h_subj[LEN]; /* Subject: */
char note_h_from[LEN]; /* From: */
char note_h_org[LEN]; /* Organization: */
char note_h_newsgroups[LEN]; /* Newsgroups: */
char note_h_messageid[LEN]; /* Message-ID: */
char note_h_distrib[LEN]; /* Distribution: */
char note_h_followup[LEN]; /* Followup-To: */
int note_line;
int note_page; /* what page we're on */
long note_mark[MAX_PAGES]; /* ftells on beginnings of pages */
FILE *note_fp; /* the body of the current article */
int note_end; /* we're done showing this article */
int rotate; /* 0=normal, 13=rot13 decode */
struct stat note_stat; /* so we can tell how big it is */
char note_full_name[100];
char note_from_addr[100];
int last_resp; /* current & previous article for - command */
int this_resp;
int glob_respnum;
char *glob_page_group;
extern int cur_groupnum;
#ifdef SIGTSTP
void
page_susp(i)
int i;
{
Raw(FALSE);
putchar('\n');
signal(SIGTSTP, SIG_DFL);
kill(0, SIGTSTP);
signal(SIGTSTP, page_susp);
mail_setup();
Raw(TRUE);
redraw_page(glob_respnum, glob_page_group);
}
#endif
show_page(respnum, group, group_path)
int respnum;
char *group;
char *group_path;
{
char ch;
int n;
long art;
restart:
glob_respnum = respnum;
glob_page_group = group;
#ifdef SIGTSTP
signal(SIGTSTP, page_susp);
#endif
if (respnum != this_resp) { /* remember current & previous */
last_resp = this_resp; /* articles for - command */
this_resp = respnum;
}
rotate = 0; /* normal mode, not rot13 */
art = arts[respnum].artnum;
arts[respnum].unread = 0; /* mark article as read */
open_note(art, group_path);
if (note_page == NOTE_UNAVAIL) {
ClearScreen();
printf("[Article %ld unvailable]\r\r", art);
fflush(stdout);
} else
show_note_page(respnum, group);
while (1) {
ch = ReadCh();
if (ch >= '0' && ch <= '9') {
n = prompt_response(ch, respnum);
if (n != -1) {
respnum = n;
goto restart;
}
} else switch (ch) {
case '|': /* pipe article into command */
pipe_article();
redraw_page(respnum, group);
break;
case 'I': /* toggle inverse video */
inverse_okay = !inverse_okay;
if (inverse_okay)
info_message("Inverse video enabled");
else
info_message("Inverse video disabled");
goto pager_ctrlr;
break;
case 's':
save_art_to_file();
break;
case 'S':
save_thread_to_file(respnum, group_path);
break;
case ctrl('X'):
case '%': /* toggle rot-13 mode */
if (rotate)
rotate = 0;
else
rotate = 13;
goto pager_ctrlr;
break;
case 'P': /* previous unread article */
n = prev_unread(prev_response(respnum));
if (n == -1)
info_message("No previous unread article");
else {
note_cleanup();
respnum = n;
goto restart;
}
break;
case 'F': /* post a followup to this article */
if (post_response(group, TRUE)) {
update_newsrc(group,
my_group[cur_groupnum]);
n = which_base(respnum);
note_cleanup();
index_group(group, group_path);
read_newsrc_line(group);
respnum = choose_resp(n, nresp(n));
goto restart;
} else
redraw_page(respnum, group);
break;
case 'f': /* post a followup to this article */
if (post_response(group, FALSE)) {
update_newsrc(group,
my_group[cur_groupnum]);
n = which_base(respnum);
note_cleanup();
index_group(group, group_path);
read_newsrc_line(group);
respnum = choose_resp(n, nresp(n));
goto restart;
} else
redraw_page(respnum, group);
break;
case 'z': /* mark article as unread (to return) */
arts[respnum].unread = 2;
info_message("Article marked as unread");
break;
case 'K': /* mark rest of thread as read */
for (n = respnum; n >= 0; n = arts[n].thread)
arts[n].unread = 0;
n = next_unread(next_response(respnum));
if (n == -1)
goto return_to_index;
else {
note_cleanup();
respnum = n;
goto restart;
}
break;
case 'i': /* return to index page */
return_to_index:
note_cleanup();
return( which_base(respnum) );
case 't': /* return to group selection page */
note_cleanup();
return -1;
case ctrl('R'): /* redraw beginning of article */
pager_ctrlr:
if (note_page == NOTE_UNAVAIL) {
ClearScreen();
printf("[Article %ld unvailable]\r\n",
arts[respnum].artnum);
fflush(stdout);
} else {
note_page = 0;
note_end = FALSE;
fseek(note_fp, note_mark[0], 0);
show_note_page(respnum, group);
}
break;
case '!':
shell_escape();
redraw_page(respnum, group);
break;
case '\b':
case 'b': /* back a page */
if (note_page == NOTE_UNAVAIL
|| note_page <= 1) {
note_cleanup();
n = prev_response(respnum);
if (n == -1)
return( which_resp(respnum) );
respnum = n;
goto restart;
} else {
note_page -= 2;
note_end = FALSE;
fseek(note_fp, note_mark[note_page], 0);
show_note_page(respnum, group);
}
break;
case 'm': /* mail article to somebody */
mail_to_someone();
redraw_page(respnum, group);
break;
case 'r': /* reply to author through mail */
mail_to_author(FALSE);
redraw_page(respnum, group);
break;
case 'R': /* reply to author, copy text */
mail_to_author(TRUE);
redraw_page(respnum, group);
break;
case '-': /* show last viewed article */
if (last_resp < 0) {
info_message("No last message");
break;
}
note_cleanup();
respnum = last_resp;
goto restart;
case 'p': /* previous article */
note_cleanup();
n = prev_response(respnum);
if (n == -1)
return( which_resp(respnum) );
respnum = n;
goto restart;
case 'n': /* skip to next article */
note_cleanup();
n = next_response(respnum);
if (n == -1)
return( which_base(respnum) );
respnum = n;
goto restart;
case 'k':
if (note_page == NOTE_UNAVAIL) {
n = next_unread(next_response(respnum));
if (n == -1)
return( which_base(respnum) );
respnum = n;
goto restart;
} else {
note_cleanup();
n = next_unread(next_response(respnum));
if (n == -1)
return( which_base(respnum) );
respnum = n;
goto restart;
}
break;
case ' ': /* next page or response */
if (note_page == NOTE_UNAVAIL) {
n = next_response(respnum);
if (n == -1)
return( which_base(respnum) );
respnum = n;
goto restart;
} else if (note_end) {
note_cleanup();
n = next_response(respnum);
if (n == -1)
return( which_base(respnum) );
respnum = n;
goto restart;
} else
show_note_page(respnum, group);
break;
case '\t': /* next page or unread response */
if (note_page == NOTE_UNAVAIL) {
n = next_unread(next_response(respnum));
if (n == -1)
return( which_base(respnum) );
respnum = n;
goto restart;
} else if (note_end) {
note_cleanup();
n = next_unread(next_response(respnum));
if (n == -1)
return( which_base(respnum) );
respnum = n;
goto restart;
} else
show_note_page(respnum, group);
break;
case 'N': /* next unread article */
n = next_unread(next_response(respnum));
if (n == -1)
info_message("No next unread article");
else {
note_cleanup();
respnum = n;
goto restart;
}
break;
case '\r':
case '\n': /* go to start of next thread */
note_cleanup();
n = next_basenote(respnum);
if (n == -1)
return( which_base(respnum) );
respnum = n;
goto restart;
case 'q': /* quit */
return -2;
case 'H': /* show article headers */
if (note_page == NOTE_UNAVAIL) {
n = next_response(respnum);
if (n == -1)
return( which_base(respnum) );
respnum = n;
goto restart;
} else {
note_page = 0;
note_end = FALSE;
fseek(note_fp, 0L, 0);
show_note_page(respnum, group);
}
break;
case 'h':
tass_page_help();
redraw_page(respnum, group);
break;
default:
info_message("Bad command. Type 'h' for help.");
}
}
}
note_cleanup() {
if (note_page != NOTE_UNAVAIL)
fclose(note_fp);
}
redraw_page(respnum, group)
int respnum;
char *group;
{
if (note_page == NOTE_UNAVAIL) {
ClearScreen();
printf("[Article %ld unvailable]\r\r", arts[respnum].artnum);
fflush(stdout);
} else if (note_page > 0) {
note_page--;
fseek(note_fp, note_mark[note_page], 0);
show_note_page(respnum, group);
}
}
show_note_page(respnum, group)
int respnum;
char *group;
{
char buf[LEN];
char buf2[LEN+50];
int percent;
char *p, *q;
int i, j;
int ctrl_L; /* form feed character detected */
ClearScreen();
note_line = 1;
if (note_page == 0)
show_first_header(respnum, group);
else
show_cont_header(respnum);
ctrl_L = FALSE;
while (note_line < LINES) {
if (fgets(buf, LEN, note_fp) == NULL) {
note_end = TRUE;
break;
}
buf[LEN-1] = '\0';
if (rotate)
for (p = buf, q = buf2;
*p && *p != '\n' && q<&buf2[LEN]; p++) {
if (*p == '\b' && q > buf2) {
q--;
} else if (*p == 12) { /* ^L */
*q++ = '^';
*q++ = 'L';
ctrl_L = TRUE;
} else if (*p == '\t') {
i = q - buf2;
j = (i|7) + 1;
while (i++ < j)
*q++ = ' ';
} else if (*p & 0x7F < 32) {
*q++ = '^';
*q++ = (*p & 0x7F) + '@';
} else if (*p >= 'A' && *p <= 'Z')
*q++ = 'A' + (*p - 'A' + rotate) % 26;
else if (*p >= 'a' && *p <= 'z')
*q++ = 'a' + (*p - 'a' + rotate) % 26;
else
*q++ = *p;
}
else
for (p = buf, q = buf2;
*p && *p != '\n' && q<&buf2[LEN]; p++) {
if (*p == '\b' && q > buf2) {
q--;
} else if (*p == 12) { /* ^L */
*q++ = '^';
*q++ = 'L';
ctrl_L = TRUE;
} else if (*p == '\t') {
i = q - buf2;
j = (i|7) + 1;
while (i++ < j)
*q++ = ' ';
} else if ((*p & 0x7F) < 32) {
*q++ = '^';
*q++ = (*p & 0x7F) + '@';
} else
*q++ = *p;
}
*q = '\0';
printf("%s\r\n", buf2);
#if 1
note_line += (strlen(buf2) / COLS) + 1;
#else
if (*buf2)
note_line += (strlen(buf2) + COLS) / (COLS+1);
else
note_line++;
#endif
if (ctrl_L)
break;
}
note_mark[++note_page] = ftell(note_fp);
MoveCursor(LINES, MORE_POS);
/* StartInverse(); */
if (note_end) {
if (arts[respnum].thread != -1)
printf("-- next response --");
else
printf("-- last response --");
} else {
if (note_stat.st_size > 0) {
percent = note_mark[note_page] * 100 / note_stat.st_size;
printf("--More--(%d%%)", percent);
} else
printf("--More--");
}
/* EndInverse(); */
fflush(stdout);
}
show_first_header(respnum, group)
int respnum;
char *group;
{
int whichresp;
int x_resp;
char buf[200];
char tmp[200];
int pos, i;
int n;
whichresp = which_resp( respnum );
x_resp = nresp( which_base(respnum) );
ClearScreen();
strcpy(buf, note_h_date);
pos = (COLS - strlen(group)) / 2;
for (i = strlen(buf); i < pos; i++)
buf[i] = ' ';
buf[i] = '\0';
strcat(buf, group);
for (i = strlen(buf); i < RIGHT_POS; i++)
buf[i] = ' ';
buf[i] = '\0';
printf("%sNote %3d of %3d\r\n", buf, which_base(respnum) + 1, top_base);
sprintf(buf, "Article %ld ", arts[respnum].artnum);
n = strlen(buf);
fputs(buf, stdout);
pos = (COLS - strlen( note_h_subj )) / 2 - 2;
if (pos > n)
MoveCursor(1, pos);
else
MoveCursor(1, n);
StartInverse();
strcpy(buf, note_h_subj);
buf[RIGHT_POS - 2 - n] = '\0';
fputs(buf, stdout);
EndInverse();
MoveCursor(1, RIGHT_POS);
if (whichresp)
printf("Resp %3d of %3d\r\n", whichresp, x_resp);
else {
if (x_resp == 0)
printf("No responses\r\n");
else if (x_resp == 1)
printf("1 Response\r\n");
else
printf("%d Responses\r\n", x_resp);
}
if (*note_h_org)
sprintf(tmp, "%s at %s", note_full_name, note_h_org);
else
strcpy(tmp, note_full_name);
tmp[79] = '\0';
sprintf(buf, "%s ", note_from_addr);
pos = COLS - 1 - strlen(tmp);
if (strlen(buf) + strlen(tmp) >= COLS - 1) {
strncat(buf, tmp, COLS - 1 - strlen(buf));
buf[COLS - 1] = '\0';
} else {
for (i = strlen(buf); i < pos; i++)
buf[i] = ' ';
buf[i] = '\0';
strcat(buf, tmp);
}
printf("%s\r\n\r\n", buf);
note_line += 4;
}
show_cont_header(respnum)
int respnum;
{
int whichresp;
int whichbase;
char buf[200];
whichresp = which_resp(respnum);
whichbase = which_base(respnum);
assert (whichbase < top_base);
if (whichresp)
sprintf(buf, "Note %d of %d, Resp %d (page %d): %s",
whichbase + 1,
top_base,
whichresp,
note_page + 1,
note_h_subj);
else
sprintf(buf, "Note %d of %d (page %d): %s",
whichbase + 1,
top_base,
note_page + 1,
note_h_subj);
buf[COLS] = '\0';
printf("%s\r\n\r\n", buf);
note_line += 2;
}
open_note(art, group_path)
long art;
char *group_path;
{
char buf[1025];
note_page = 0;
sprintf(buf, "/usr/spool/news/%s/%ld", group_path, art);
if (stat(buf, ¬e_stat) < 0)
note_stat.st_size = 0;
note_fp = fopen(buf, "r");
if (note_fp == NULL) {
fprintf(stderr, "can't open %s: ", buf);
perror("");
note_page = NOTE_UNAVAIL;
return;
}
note_h_from[0] = '\0';
note_h_path[0] = '\0';
note_h_subj[0] = '\0';
note_h_org[0] = '\0';
note_h_date[0] = '\0';
note_h_newsgroups[0] = '\0';
note_h_messageid[0] = '\0';
note_h_distrib[0] = '\0';
note_h_followup[0] = '\0';
while (fgets(buf, 1024, note_fp) != NULL) {
buf[1024] = '\0';
buf[strlen(buf)-1] = '\0';
if (*buf == '\0')
break;
if (strncmp(buf, "From: ", 6) == 0) {
strncpy(note_h_from, &buf[6], LEN);
note_h_from[LEN-1] = '\0';
} else if (strncmp(buf, "Path: ", 6) == 0) {
strncpy(note_h_path, &buf[6], LEN);
note_h_path[LEN-1] = '\0';
} else if (strncmp(buf, "Subject: ", 9) == 0) {
strncpy(note_h_subj, &buf[9], LEN);
note_h_subj[LEN-1] = '\0';
} else if (strncmp(buf, "Organization: ", 14) == 0) {
strncpy(note_h_org, &buf[14], LEN);
note_h_org[LEN-1] = '\0';
} else if (strncmp(buf, "Date: ", 6) == 0) {
strncpy(note_h_date, &buf[6], LEN);
note_h_date[LEN-1] = '\0';
} else if (strncmp(buf, "Newsgroups: ", 12) == 0) {
strncpy(note_h_newsgroups, &buf[12], LEN);
note_h_newsgroups[LEN-1] = '\0';
} else if (strncmp(buf, "Message-ID: ", 12) == 0) {
strncpy(note_h_messageid, &buf[12], LEN);
note_h_messageid[LEN-1] = '\0';
} else if (strncmp(buf, "Distribution: ", 14) == 0) {
strncpy(note_h_distrib, &buf[14], LEN);
note_h_distrib[LEN-1] = '\0';
} else if (strncmp(buf, "Followup-To: ", 13) == 0) {
strncpy(note_h_followup, &buf[13], LEN);
note_h_followup[LEN-1] = '\0';
}
}
note_page = 0;
note_mark[0] = ftell(note_fp);
parse_from(note_h_from, note_from_addr, note_full_name);
note_end = FALSE;
return;
}
prompt_response(ch, respnum)
int respnum;
{
int num;
clear_message();
if ((num = parse_num(ch, "Read response> ")) == -1) {
clear_message();
return(-1);
}
return choose_resp( which_base(respnum), num );
}
/*
* return response number n from thread i
*/
choose_resp(i, n)
int i;
int n;
{
int j;
j = base[i];
while (n-- && arts[j].thread >= 0)
j = arts[j].thread;
return j;
}
/*
* Parse various From: lines into the component mail addresses and
* real names
*/
parse_from(str, addr, name)
char *str;
char *addr;
char *name;
{
while (*str && *str != ' ')
*addr++ = *str++;
*addr = '\0';
if (*str++ == ' ') {
if (*str++ == '(') {
if (*str == '"')
str++; /* Kill "quotes around names" */
/* But don't touch quotes inside the */
/* Name (that's what that nonsense */
/* below is for */
while (*str && *str != ')' && !(*str=='"'&&str[1]==')'))
*name++ = *str++;
}
}
*name = '\0';
}
/*
* Find the previous response. Go to the last response in the previous
* thread if we go past the beginning of this thread.
*/
prev_response(n)
int n;
{
int resp;
int i;
resp = which_resp(n);
if (resp > 0)
return choose_resp( which_base(n), resp-1 );
i = which_base(n) - 1;
if (i < 0)
return -1;
return choose_resp( i, nresp(i) );
}
/*
* Find the next response. Go to the next basenote if there
* are no more responses in this thread
*/
next_response(n)
int n;
{
int i;
if (arts[n].thread >= 0)
return arts[n].thread;
i = which_base(n) + 1;
if (i >= top_base)
return -1;
return base[i];
}
/*
* Given a respnum (index into arts[]), find the respnum of the
* next basenote
*/
next_basenote(n)
int n;
{
int i;
i = which_base(n) + 1;
if (i >= top_base)
return -1;
return base[i];
}
tass_page_help() {
char ch;
page_help_start:
ClearScreen();
center_line(0, TASS_HEADER);
center_line(1, "Article Pager Commands (page 1 of 2)");
MoveCursor(3, 0);
printf("0 Read the base article in this thread\r\n");
printf("4 Read response 4 in this thread\r\n");
printf("<CR> Skip to next base article\r\n");
printf("<TAB> Advance to next page or unread article\r\n");
printf("b Back a page\r\n");
printf("f Post a followup\r\n");
printf("F Post a followup, copy text)\r\n");
printf("H Show article headers\r\n");
printf("i Return to index page\r\n");
printf("k Mark article as read & advance to next unread\r\n");
printf("K Mark rest of thread as read && advance to next unread\r\n");
printf("m Mail this article to someone\r\n");
printf("n Skip to the next article)\r\n");
printf("N Skip to the next unread article\r\n");
printf("p Go to the previous article\r\n");
printf("P Go to the previous unread article\r\n");
center_line(LINES, "-- hit space for more commands --");
ch = ReadCh();
if (ch != ' ')
return;
ClearScreen();
center_line(0, TASS_HEADER);
center_line(1, "Article Pager Commands (page 2 of 2)");
MoveCursor(3, 0);
printf("q Quit\r\n");
printf("r Reply through mail to author\r\n");
printf("R Reply through mail to author, copy text\r\n");
printf("s Save article to file\r\n");
printf("S Save thread to file\r\n");
printf("t Return to group selection index\r\n");
printf("z Mark article as unread\r\n");
printf("^R Redisplay first page of article\r\n");
printf("%%, ^X Toggle rot-13 decoding for this article\r\n");
printf("- Show last message\r\n");
printf("| Pipe article into command\r\n");
center_line(LINES, "-- hit any key --");
ch = ReadCh();
if (ch == 'b')
goto page_help_start;
}
/*
* Read a file grabbing the address given for To: and
* sticking it in mail_to
*/
find_new_to(nam, mail_to)
char *nam;
char *mail_to;
{
FILE *fp;
char buf[LEN];
char buf2[LEN];
char dummy[LEN];
fp = fopen(nam, "r");
if (fp == NULL)
return;
while (fgets(buf, 1024, fp) != NULL) {
if (*buf == '\n')
break;
if (strncmp(buf, "To: ", 4) == 0) {
buf[strlen(buf)-1] = '\0';
strncpy(buf2, &buf[4], LEN);
buf2[LEN-1] = '\0';
parse_from(buf2, mail_to, dummy);
break;
}
}
fclose(fp);
}
mail_to_someone() {
char nam[100];
FILE *fp;
char ch;
char buf[200];
char mail_to[LEN+1];
char subj[LEN+1];
setuid(real_uid);
setgid(real_gid);
if (!parse_string("Mail article to: ", mail_to))
return;
if (mail_to[0] == '\0')
return;
sprintf(nam, "%s/.letter", homedir);
if ((fp = fopen(nam, "w")) == NULL) {
fprintf(stderr, "can't open %s: ", nam);
perror("");
return(FALSE);
}
chmod(nam, 0600);
fprintf(fp, "To: %s\n", mail_to);
fprintf(fp, "Subject: %s\n", note_h_subj);
if (*note_h_followup)
fprintf(fp, "Newsgroups: %s\n\n", note_h_followup);
else
fprintf(fp, "Newsgroups: %s\n", note_h_newsgroups);
if (*my_org)
fprintf(fp, "Organization: %s\n", my_org);
fputs("\n", fp);
fseek(note_fp, 0L, 0);
copy_fp(note_fp, fp, "");
fclose(fp);
while (1) {
do {
MoveCursor(LINES, 0);
fputs("abort, edit, send: ", stdout);
fflush(stdout);
ch = ReadCh();
} while (ch != 'a' && ch != 'e' && ch != 's');
switch (ch) {
case 'e':
invoke_editor(nam);
break;
case 'a':
return FALSE;
case 's':
/*
* Open letter an get the To: line in case they changed it with
* the editor
*/
find_new_to(nam, mail_to);
printf("\nMailing to %s...", mail_to);
fflush(stdout);
sprintf(buf, "%s \"%s\" < %s", MAILER,
mail_to, nam);
if (invoke_cmd(buf)) {
printf("Message sent\n");
fflush(stdout);
goto mail_to_someone_done;
} else {
printf("Command failed: %s\n", buf);
fflush(stdout);
break;
}
}
}
mail_to_someone_done:
setuid(tass_uid);
setgid(tass_gid);
continue_prompt();
return TRUE;
}
mail_to_author(copy_text)
int copy_text;
{
char nam[100];
FILE *fp;
char ch;
char buf[200];
char mail_to[LEN+1];
setuid(real_uid);
setgid(real_gid);
printf("\r\nMailing to %s...\r\n\r\n", note_h_from);
sprintf(nam, "%s/.letter", homedir);
if ((fp = fopen(nam, "w")) == NULL) {
fprintf(stderr, "can't open %s: ", nam);
perror("");
return(FALSE);
}
chmod(nam, 0600);
fprintf(fp, "To: %s\n", note_h_from);
fprintf(fp, "Subject: Re: %s\n", eat_re(note_h_subj) );
fprintf(fp, "Newsgroups: %s\n", note_h_newsgroups);
if (*my_org)
fprintf(fp, "Organization: %s\n", my_org);
fputs("\n", fp);
if (copy_text) { /* if "copy_text" */
fprintf(fp, "In article %s you write:\n", note_h_messageid);
fseek(note_fp, note_mark[0], 0);
copy_fp(note_fp, fp, "> ");
}
fclose(fp);
ch = 'e';
while (1) {
switch (ch) {
case 'e':
invoke_editor(nam);
break;
case 'a':
return FALSE;
case 's':
strcpy(mail_to, note_from_addr);
find_new_to(nam, mail_to);
printf("\nMailing to %s... ", mail_to);
fflush(stdout);
sprintf(buf, "/usr/bin/rmail \"%s\" < %s",
mail_to, nam);
if (invoke_cmd(buf)) {
printf("Message sent\n");
fflush(stdout);
goto mail_to_author_done;
} else {
printf("Command failed: %s\n", buf);
fflush(stdout);
break;
}
}
do {
MoveCursor(LINES, 0);
fputs("abort, edit, send: ", stdout);
fflush(stdout);
ch = ReadCh();
} while (ch != 'a' && ch != 'e' && ch != 's');
}
mail_to_author_done:
setuid(tass_uid);
setgid(tass_gid);
continue_prompt();
return TRUE;
}
post_response(group, respnum)
int respnum;
{
FILE *fp;
char nam[100];
char ch;
char buf[200];
int post_anyway = FALSE;
if (*note_h_followup && strcmp(note_h_followup, "poster") == 0) {
clear_message();
MoveCursor(LINES,0);
printf("Note: Responses have been directed to the poster");
if (!prompt_yn("Post anyway? (y/n): "))
return FALSE;
*note_h_followup = '\0';
} else if (*note_h_followup && strcmp(note_h_followup, group) != 0) {
clear_message();
MoveCursor(LINES,0);
printf("Note: Responses have been directed to %s\r\n\r\n",
note_h_followup);
if (!prompt_yn("Continue? (y/n): "))
return FALSE;
}
setuid(real_uid);
setgid(real_gid);
sprintf(nam, "%s/.article", homedir);
if ((fp = fopen(nam, "w")) == NULL) {
fprintf(stderr, "can't open %s: ", nam);
perror("");
return FALSE;
}
chmod(nam, 0600);
fprintf(fp, "Subject: Re: %s\n", eat_re(note_h_subj));
if (*note_h_followup && strcmp(note_h_followup, "poster") != 0)
fprintf(fp, "Newsgroups: %s\n", note_h_followup);
else
fprintf(fp, "Newsgroups: %s\n", note_h_newsgroups);
if (*my_org)
fprintf(fp, "Organization: %s\n", my_org);
if (note_h_distrib != '\0')
fprintf(fp, "Distribution: %s\n", note_h_distrib);
fprintf(fp, "References: %s\n", note_h_messageid);
fprintf(fp, "\n");
if (respnum) { /* if "copy_text" */
fprintf(fp, "%s writes:\n", note_h_from);
fseek(note_fp, note_mark[0], 0);
copy_fp(note_fp, fp, "> ");
}
fclose(fp);
ch = 'e';
while (1) {
switch (ch) {
case 'e':
invoke_editor(nam);
break;
case 'a':
return FALSE;
case 'p':
printf("Posting... ");
fflush(stdout);
sprintf(buf, "%s/inews -h < %s", LIBDIR, nam);
if (invoke_cmd(buf)) {
printf("article posted\n");
fflush(stdout);
goto post_response_done;
} else {
printf("article rejected\n");
fflush(stdout);
break;
}
}
do {
MoveCursor(LINES, 0);
fputs("abort, edit, post: ", stdout);
fflush(stdout);
ch = ReadCh();
} while (ch != 'a' && ch != 'e' && ch != 'p');
}
post_response_done:
setuid(tass_uid);
setgid(tass_gid);
continue_prompt();
return TRUE;
}
save_art_to_file()
{
char nam[LEN];
FILE *fp;
char *p;
if (!parse_string("Save article to file: ", nam))
return;
if (nam[0] == '\0')
return;
for (p = nam; *p && (*p == ' ' || *p == '\t'); p++) ;
if (!*p)
return;
setuid(real_uid);
setgid(real_gid);
if ((fp = fopen(p, "a+")) == NULL) {
fprintf(stderr, "can't open %s: ", nam);
perror("");
info_message("-- article not saved --");
setuid(real_uid);
setgid(real_gid);
return;
}
MoveCursor(LINES, 0);
fputs("Saving...", stdout);
fflush(stdout);
fprintf(fp, "From %s %s\n", note_h_path, note_h_date);
fseek(note_fp, 0L, 0);
copy_fp(note_fp, fp, "");
fputs("\n", fp);
fclose(fp);
setuid(real_uid);
setgid(real_gid);
info_message("-- article saved --");
}
save_thread_to_file(respnum, group_path)
long respnum;
char *group_path;
{
char nam[LEN];
FILE *fp;
FILE *art;
int i;
char buf[8192];
int b;
int count = 0;
char *p;
b = which_base(respnum);
if (!parse_string("Save thread to file: ", nam))
return;
if (nam[0] == '\0')
return;
for (p = nam; *p && (*p == ' ' || *p == '\t'); p++) ;
if (!*p)
return;
setuid(real_uid);
setgid(real_gid);
if ((fp = fopen(nam, "a+")) == NULL) {
fprintf(stderr, "can't open %s: ", nam);
perror("");
info_message("-- thread not saved --");
setuid(real_uid);
setgid(real_gid);
return;
}
MoveCursor(LINES, 0);
fputs("Saving... ", stdout);
fflush(stdout);
note_cleanup();
for (i = base[b]; i >= 0; i = arts[i].thread) {
open_note(arts[i].artnum, group_path);
fprintf(fp, "From %s %s\n", note_h_path, note_h_date);
fseek(note_fp, 0L, 0);
copy_fp(note_fp, fp, "");
fputs("\n", fp);
note_cleanup();
printf("\b\b\b\b%4d", ++count);
fflush(stdout);
}
fclose(fp);
setuid(real_uid);
setgid(real_gid);
info_message("-- thread saved --");
open_note(arts[respnum].artnum, group_path);
}
pipe_article() {
char command[LEN];
FILE *fp;
if (!parse_string("Pipe to command: ", command))
return;
if (command[0] == '\0')
return;
fp = popen(command, "w");
if (fp == NULL) {
fprintf(stderr, "command failed: ");
perror("");
goto pipe_article_done;
}
fseek(note_fp, 0L, 0);
copy_fp(note_fp, fp, "");
pclose(fp);
pipe_article_done:
continue_prompt();
}
@EOF
chmod 644 page.c
echo x - prompt.c
cat >prompt.c <<'@EOF'
#include <stdio.h>
#include "tass.h"
/*
* parse_num
* get a number from the user
* Return -1 if missing or bad number typed
*/
parse_num(ch, prompt)
char ch;
char *prompt;
{
char buf[40];
int len;
int i;
int num;
MoveCursor(LINES,0);
printf("%s %c",prompt,ch);
fflush(stdout);
buf[0] = ch;
buf[1] = '\0';
len = 1;
ch = ReadCh();
while (ch != '\n'&& ch != '\r') {
if (ch >= '0' && ch <= '9' && len < 4) {
buf[len++] = ch;
buf[len] = '\0';
putchar(ch);
} else if (ch == 8 || ch == 127) {
if (len) {
len--;
buf[len] = '\0';
putchar('\b');
putchar(' ');
putchar('\b');
} else {
MoveCursor(LINES, 0);
CleartoEOLN();
return(-1);
}
} else if (ch == 21) { /* control-U */
for (i = len;i>0;i--) {
putchar('\b');
putchar(' ');
putchar('\b');
}
buf[0] = '\0';
len = 0;
} else
putchar(7);
fflush(stdout);
ch = ReadCh();
}
MoveCursor(LINES, 0);
CleartoEOLN();
if (len) {
num = atoi(buf);
return(num);
} else
return(-1);
}
/*
* parse_string
* get a string from the user
* Return TRUE if a valid string was typed, FALSE otherwise
*/
parse_string(prompt, buf)
char *prompt;
char *buf;
{
int len;
int i;
char ch;
clear_message();
MoveCursor(LINES,0);
printf("%s", prompt);
fflush(stdout);
buf[0] = '\0';
len = 0;
ch = ReadCh();
while (ch != '\n' && ch != '\r') {
if (ch >= ' ' && len < 60) {
buf[len++] = ch;
buf[len] = '\0';
putchar(ch);
} else if (ch == 8 || ch == 127) {
if (len) {
len--;
buf[len] = '\0';
putchar('\b');
putchar(' ');
putchar('\b');
} else {
MoveCursor(LINES, 0);
CleartoEOLN();
return(FALSE);
}
} else if (ch == 21) { /* control-U */
for (i = len;i>0;i--) {
putchar('\b');
putchar(' ');
putchar('\b');
}
buf[0] = '\0';
len = 0;
} else
putchar(7);
fflush(stdout);
ch = ReadCh();
}
MoveCursor(LINES,0);
CleartoEOLN();
return TRUE;
}
prompt_yn(prompt)
char *prompt;
{
char ch;
clear_message();
MoveCursor(LINES,0);
printf("%s", prompt);
fflush(stdout);
ch = ReadCh();
clear_message();
if (ch == 'y' || ch == 'Y')
return TRUE;
return FALSE;
}
continue_prompt() {
printf("-Hit return to continue-");
fflush(stdout);
while (ReadCh() != '\n') ;
}
@EOF
chmod 644 prompt.c
echo x - screen.c
cat >screen.c <<'@EOF'
#include <stdio.h>
#include "tass.h"
info_message(msg)
char *msg;
{
clear_message(); /* Clear any old messages hanging around */
center_line(LINES, msg); /* center the message at screen bottom */
MoveCursor(LINES, 0);
}
clear_message()
{
MoveCursor(LINES, 0);
CleartoEOLN();
}
center_line(line, str)
int line;
char *str;
{
int pos;
pos = (COLS - strlen(str)) / 2;
MoveCursor(line, pos);
printf("%s", str);
fflush(stdout);
}
draw_arrow(line)
int line;
{
MoveCursor(line, 0);
printf("->");
fflush(stdout);
MoveCursor(LINES, 0);
}
erase_arrow(line)
int line;
{
MoveCursor(line, 0);
printf(" ");
fflush(stdout);
}
@EOF
chmod 644 screen.c
echo x - select.c
cat >select.c <<'@EOF'
#include <stdio.h>
#include <signal.h>
#include "tass.h"
int first_group_on_screen;
int last_group_on_screen;
int cur_groupnum = 0;
extern int index_point;
int space_mode;
extern char *cvers;
char group_search_string[LEN+1];
#ifdef SIGTSTP
void
select_susp(i)
int i;
{
Raw(FALSE);
putchar('\n');
signal(SIGTSTP, SIG_DFL);
kill(0, SIGTSTP);
signal(SIGTSTP, select_susp);
Raw(TRUE);
mail_setup();
group_selection_page();
}
#endif
selection_index()
{
char ch;
int n;
int i;
char buf[200];
group_selection_page(); /* display group selection page */
while (1) {
ch = ReadCh();
if (ch > '0' && ch <= '9') {
prompt_group_num(ch);
} else switch (ch) {
case 'c': /* catchup--mark all articles as read */
if (prompt_yn("Mark group as read? (y/n): ")) {
unread[cur_groupnum] = 0;
mark_group_read(
active[my_group[cur_groupnum]].name,
my_group[cur_groupnum]);
group_selection_page();
}
break;
case ctrl('K'):
if (local_top <= 0) {
info_message("No groups to delete");
break;
}
delete_group(
active[my_group[cur_groupnum]].name);
active[my_group[cur_groupnum]].flag = NOTGOT;
local_top--;
for (i = cur_groupnum; i < local_top; i++) {
my_group[i] = my_group[i+1];
unread[i] = unread[i+1];
}
if (cur_groupnum >= local_top)
cur_groupnum = local_top - 1;
group_selection_page();
break;
case ctrl('Y'):
undel_group();
group_selection_page();
break;
case 'I': /* toggle inverse video */
inverse_okay = !inverse_okay;
if (inverse_okay)
info_message("Inverse video enabled");
else
info_message("Inverse video disabled");
break;
case ctrl('R'): /* reset .newsrc */
if (prompt_yn("Reset newsrc? (y/n): ")) {
reset_newsrc();
cur_groupnum = 0;
group_selection_page();
}
break;
case '$': /* reread .newsrc, no unsub groups */
cur_groupnum = 0;
local_top = 0;
for (i = 0; i < num_active; i++)
active[i].flag = NOTGOT;
read_newsrc(TRUE);
group_selection_page();
break;
case 's': /* subscribe to current group */
MoveCursor(INDEX_TOP +
(cur_groupnum-first_group_on_screen), 3);
putchar(' ');
fflush(stdout);
MoveCursor(LINES, 0);
subscribe(active[my_group[cur_groupnum]].name,
':', my_group[cur_groupnum], FALSE);
sprintf(buf, "subscribed to %s",
active[my_group[cur_groupnum]].name);
info_message(buf);
break;
case 'u': /* unsubscribe to current group */
MoveCursor(INDEX_TOP +
(cur_groupnum-first_group_on_screen), 3);
putchar('u');
fflush(stdout);
MoveCursor(LINES, 0);
subscribe(active[my_group[cur_groupnum]].name,
'!', my_group[cur_groupnum], FALSE);
sprintf(buf, "unsubscribed to %s",
active[my_group[cur_groupnum]].name);
info_message(buf);
break;
case ' ':
clear_message();
break;
case '\t':
for (i = cur_groupnum; i < local_top; i++)
if (unread[i] != 0)
break;
if (i >= local_top) {
info_message("No more groups to read");
break;
}
erase_group_arrow();
cur_groupnum = i;
if (cur_groupnum >= last_group_on_screen)
group_selection_page();
else
draw_group_arrow();
space_mode = TRUE;
goto go_into_group;
case 'g': /* prompt for a new group name */
n = choose_new_group();
if (n >= 0) {
erase_group_arrow();
cur_groupnum = n;
if (cur_groupnum < first_group_on_screen
|| cur_groupnum >= last_group_on_screen)
group_selection_page();
else
draw_group_arrow();
}
break;
case 27: /* (ESC) common arrow keys */
ch = ReadCh();
if (ch == '[' || ch == 'O')
ch = ReadCh();
switch (ch) {
case 'A':
case 'D':
case 'i':
goto select_up;
case 'B':
case 'I':
case 'C':
goto select_down;
}
break;
case 'y': /* pull in rest of groups from active */
n = local_top;
for (i = 0; i < num_active; i++)
active[i].flag = NOTGOT;
read_newsrc(FALSE);
for (i = 0; i < num_active; i++)
if (active[i].flag & NOTGOT) {
active[i].flag &= ~NOTGOT;
my_group[local_top] = i;
unread[local_top] = -1;
local_top++;
}
if (n < local_top) {
sprintf(buf, "Added %d group%s",
local_top - n,
local_top - n == 1 ? "" : "s");
group_selection_page();
info_message(buf);
} else
info_message("No more groups to yank in");
break;
case ctrl('U'): /* page up */
erase_group_arrow();
cur_groupnum -= NOTESLINES / 2;
if (cur_groupnum < 0)
cur_groupnum = 0;
if (cur_groupnum < first_group_on_screen
|| cur_groupnum >= last_group_on_screen)
group_selection_page();
else
draw_group_arrow();
break;
case ctrl('D'): /* page down */
erase_group_arrow();
cur_groupnum += NOTESLINES / 2;
if (cur_groupnum >= local_top)
cur_groupnum = local_top - 1;
if (cur_groupnum <= first_group_on_screen
|| cur_groupnum >= last_group_on_screen)
group_selection_page();
else
draw_group_arrow();
break;
case '!':
shell_escape();
group_selection_page();
break;
case 'v':
info_message(cvers);
break;
case ctrl('N'): /* line down */
case 'j':
select_down:
if (cur_groupnum + 1 >= local_top)
break;
if (cur_groupnum + 1 >= last_group_on_screen) {
cur_groupnum++;
group_selection_page();
} else {
erase_group_arrow();
cur_groupnum++;
draw_group_arrow();
}
break;
case ctrl('P'): /* line up */
case 'k':
select_up:
if (!cur_groupnum)
break;
if (cur_groupnum <= first_group_on_screen) {
cur_groupnum--;
group_selection_page();
} else {
erase_group_arrow();
cur_groupnum--;
draw_group_arrow();
}
break;
case 't': /* redraw */
case ctrl('W'):
case ctrl('L'):
group_selection_page();
break;
case '\r': /* go into group */
case '\n':
space_mode = FALSE;
go_into_group:
clear_message();
index_point = -1;
do {
group_page(
active[my_group[cur_groupnum]].name);
} while (index_point == -3);
group_selection_page();
break;
case '/': /* search forward */
search_group(TRUE);
break;
case '?': /* search backward */
search_group(FALSE);
break;
case 'q': /* quit */
tass_done(0);
case 'h':
tass_select_help();
group_selection_page();
break;
default:
info_message("Bad command. Type 'h' for help.");
}
}
}
group_selection_page() {
int i;
int n;
char new[10];
char subs;
#ifdef SIGTSTP
signal(SIGTSTP, select_susp);
#endif
ClearScreen();
printf("%s\r\n", nice_time()); /* print time in upper left */
if (mail_check()) { /* you have mail message */
MoveCursor(0, 66); /* in upper right */
printf("you have mail\n");
}
center_line(1, "Group Selection");
MoveCursor(INDEX_TOP, 0);
first_group_on_screen = (cur_groupnum / NOTESLINES) * NOTESLINES;
last_group_on_screen = first_group_on_screen + NOTESLINES;
if (last_group_on_screen >= local_top)
last_group_on_screen = local_top;
for (i = first_group_on_screen; i < last_group_on_screen; i++) {
switch (unread[i]) {
case -2:
strcpy(new, "? ");
break;
case -1:
strcpy(new, "- ");
break;
case 0:
strcpy(new, " ");
break;
default:
sprintf(new, "%-4d", unread[i]);
}
n = my_group[i];
if (active[n].flag & SUBS) /* subscribed? */
subs = ' ';
else
subs = 'u'; /* u next to unsubscribed groups */
printf(" %c %4d %-35s %s\r\n", subs, i+1,
active[n].name, new);
}
draw_group_arrow();
}
prompt_group_num(ch)
char ch;
{
int num;
clear_message();
if ((num = parse_num(ch, "Select group> ")) == -1) {
clear_message();
return FALSE;
}
num--; /* index from 0 (internal) vs. 1 (user) */
if (num >= local_top)
num = local_top - 1;
if (num >= first_group_on_screen
&& num < last_group_on_screen) {
erase_group_arrow();
cur_groupnum = num;
draw_group_arrow();
} else {
cur_groupnum = num;
group_selection_page();
}
return TRUE;
}
erase_group_arrow() {
erase_arrow(INDEX_TOP + (cur_groupnum-first_group_on_screen) );
}
draw_group_arrow() {
draw_arrow(INDEX_TOP + (cur_groupnum-first_group_on_screen) );
}
search_group(forward)
int forward;
{
char buf[LEN+1];
int i;
extern char *regcmp();
extern char *regex();
char *re;
char *prompt;
clear_message();
if (forward)
prompt = "/";
else
prompt = "?";
if (!parse_string(prompt, buf))
return;
if (strlen(buf))
strcpy(group_search_string, buf);
else if (!strlen(group_search_string)) {
info_message("No search pattern");
return;
}
i = cur_groupnum;
glob_name(group_search_string, buf);
if ((re = regcmp(buf, NULL)) == NULL) {
info_message("Bad search pattern");
return;
}
do {
if (forward)
i++;
else
i--;
if (i >= local_top)
i = 0;
if (i < 0)
i = local_top - 1;
if (regex(re, active[my_group[i]].name) != NULL) {
if (i >= first_group_on_screen
&& i < last_group_on_screen) {
erase_group_arrow();
cur_groupnum = i;
draw_group_arrow();
} else {
cur_groupnum = i;
group_selection_page();
}
return;
}
} while (i != cur_groupnum);
info_message("No match");
}
tass_select_help() {
ClearScreen();
center_line(0, TASS_HEADER);
center_line(1, "Group Selection Commands");
MoveCursor(3, 0);
printf("4 Select group 4\r\n");
printf("^D Page down\r\n");
printf("^R Reset .newsrc\r\n");
printf("^U Page up\r\n");
printf("^K Delete group\r\n");
printf("^Y Undelete group\r\n");
printf("<CR> Read current group\r\n");
printf("<TAB> View next unread group\r\n");
printf("c Mark group as all read\r\n");
printf("g Choose a new group by name\r\n");
printf("j Down a line\r\n");
printf("k Up a line\r\n");
printf("q Quit\r\n");
printf("s Subscribe to current group\r\n");
printf("u Unsubscribe to current group\r\n");
printf("y Yank in groups that are not in the .newsrc\r\n");
printf("$ Reread group list from .newsrc\r\n");
printf("/ Search forward for group\r\n");
printf("? Search backward for group\r\n");
center_line(LINES, "-- hit any key --");
ReadCh();
}
choose_new_group() {
char buf[LEN+1];
char *p;
int ret;
if (!parse_string("Newsgroup> ", buf))
return -1;
for (p = buf; *p && (*p == ' ' || *p == '\t'); p++) ;
if (*p == '\0')
return -1;
ret = add_group(p, TRUE);
if (ret < 0)
info_message("Group not found in active file");
return ret;
}
/*
* Add a group to the selection list (my_group[])
* Return the index of my_group[] if group is added or was already
* there. Return -1 if named group is not in active[].
*/
add_group(s, get_unread)
char *s;
int get_unread; /* look in .newsrc for sequencer unread info? */
{
long h;
int i, j;
{ /* find the hash of the group name */
char *t = s;
h = *t++;
while (*t)
h = (h * 64 + *t++) % TABLE_SIZE;
}
for (i = group_hash[h]; i >= 0; i = active[i].next)
if (strcmp(s, active[i].name) == 0) {
for (j = 0; j < local_top; j++)
if (my_group[j] == i)
return j;
active[i].flag &= ~NOTGOT; /* mark that we got it */
my_group[local_top] = i;
if (get_unread)
unread[local_top] = get_line_unread(s, i);
else
unread[local_top] = -2;
local_top++;
return local_top - 1;
}
return -1;
}
@EOF
chmod 644 select.c
echo x - tass.h
cat >tass.h <<'@EOF'
#define LIBDIR "/usr/lib/news"
#define SPOOLDIR "/usr/spool/news"
#define MAILER "/bin/rmail"
#define TRUE 1
#define FALSE 0
#define LEN 200
#define INDEX_TOP 4
#define NOTESLINES (LINES - INDEX_TOP - 2)
#define RIGHT_POS (COLS - 16)
#define MORE_POS (COLS - 20)
#define MAX_FROM 25
#define MAX_SUBJ 38
#define TABLE_SIZE 1409
/* #define MAX_SUBJ (COLS - 42) */
struct header {
long artnum;
char subject[MAX_SUBJ];
char *nore; /* pointer into subject after Re: */
char from[MAX_FROM];
int thread;
long hash;
int inthread;
int unread; /* has this article been read? */
/* 0 = read, 1 = unread, 2 = will return */
};
/*
* header.artnum:
* article number in spool directory for group
*
* header.nore
* pointer into header.subject after the Re:'s.
*
* header.hash:
* hash of the subject minus the re's. For fast subject comparison
*
* header.thread:
* initially -1
* points to another arts[] (struct header): zero and up
* -2 means article has expired (wasn't found in file search
* of spool directory for the group)
*
* header.inthread:
* FALSE for the first article in a thread, TRUE for all
* following articles in thread
*
* header.read:
* boolean, has this article been read or not
*/
struct group_ent {
char *name;
long max;
long min;
int next; /* next active entry in hash chain */
int flag;
};
#define NOTGOT 0x01 /* haven't put in my_group yet */
#define SUBS 0x02 /* subscribed to */
extern int top;
extern struct header *arts;
extern long *base;
extern int max_art;
extern char userid[LEN];
extern char homedir[LEN];
extern char indexdir[LEN];
extern char my_org[LEN];
extern char active_file[LEN];
extern char newsrc[LEN];
extern char newnewsrc[LEN];
extern char delgroups[LEN];
extern int top_base;
extern int LINES, COLS;
extern char *str_save();
extern char *my_malloc();
extern char *my_realloc();
extern int group_hash[TABLE_SIZE];
extern int num_active;
extern struct group_ent *active;
extern int *my_group;
extern int *unread;
extern int max_active;
extern int local_top;
extern char *eat_re();
extern char *nice_time();
extern int update;
extern int inverse_okay;
extern int tass_uid;
extern int tass_gid;
extern int real_uid;
extern int real_gid;
extern int local_index;
extern char *strcpy();
extern char *strncat();
extern char *strncpy();
extern long atol();
#define ctrl(c) ((c) & 0x1F)
/*
* Assertion verifier
*/
#ifdef __STDC__
#define assert(p) if(! (p)) asfail(__FILE__, __LINE__, #p); else
#else
#define assert(p) if(! (p)) asfail(__FILE__, __LINE__, "p"); else
#endif
#define TASS_HEADER "Tass 3.0"
@EOF
chmod 644 tass.h
echo x - time.c
cat >time.c <<'@EOF'
#include <sys/types.h>
#include <time.h>
nicedate(timestr, newstr)
char *timestr, *newstr;
{
int i;
for (i = 0; i <= 7; i++)
*newstr++ = timestr[i];
if (timestr[8] != ' ')
*newstr++ = timestr[8];
*newstr++ = timestr[9];
*newstr++ = ',';
*newstr++ = ' ';
for (i = 20;i <= 23; i++)
*newstr++ = timestr[i];
*newstr++ = '\0';
}
nicetime(timestr, newstr)
char *timestr, *newstr;
{
int hours;
char dayornite[3];
if (timestr[11] == ' ')
hours = timestr[12] - '0';
else
hours = (timestr[11]-'0')*10 + (timestr[12]-'0');
if (hours < 12)
strcpy(dayornite, "am");
else
strcpy(dayornite, "pm");
if (hours >= 13)
hours -= 12;
if (!hours)
hours = 12;
sprintf(newstr, "%d:%c%c%s", hours, timestr[14],
timestr[15], dayornite);
}
char *nice_time() {
char *timestr;
char the_date[17];
char the_time[8];
extern char *ctime();
long time_now;
static char buf[25];
time(&time_now);
timestr = ctime(&time_now);
nicedate(timestr, the_date);
nicetime(timestr, the_time);
sprintf(buf,"%s %s", the_date, the_time);
return(buf);
}
@EOF
chmod 644 time.c
exit 0
--
skrenta at blekko.commodore.com
More information about the Alt.sources
mailing list