msgs.c revision 102084
1161748Scperciva/*- 2161748Scperciva * Copyright (c) 1980, 1993 3161748Scperciva * The Regents of the University of California. All rights reserved. 4173441Scperciva * 5161748Scperciva * Redistribution and use in source and binary forms, with or without 6161748Scperciva * modification, are permitted provided that the following conditions 7161748Scperciva * are met: 8161748Scperciva * 1. Redistributions of source code must retain the above copyright 9161748Scperciva * notice, this list of conditions and the following disclaimer. 10161748Scperciva * 2. Redistributions in binary form must reproduce the above copyright 11161748Scperciva * notice, this list of conditions and the following disclaimer in the 12161748Scperciva * documentation and/or other materials provided with the distribution. 13161748Scperciva * 3. All advertising materials mentioning features or use of this software 14161748Scperciva * must display the following acknowledgement: 15161748Scperciva * This product includes software developed by the University of 16161748Scperciva * California, Berkeley and its contributors. 17161748Scperciva * 4. Neither the name of the University nor the names of its contributors 18161748Scperciva * may be used to endorse or promote products derived from this software 19161748Scperciva * without specific prior written permission. 20161748Scperciva * 21161748Scperciva * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22161748Scperciva * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23161748Scperciva * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24161748Scperciva * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25161748Scperciva * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26161748Scperciva * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27161748Scperciva * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28161748Scperciva * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29161748Scperciva * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30161748Scperciva * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31161748Scperciva * SUCH DAMAGE. 32161748Scperciva */ 33161748Scperciva 34161748Scperciva#ifndef lint 35161748Scpercivastatic const char copyright[] = 36161748Scperciva"@(#) Copyright (c) 1980, 1993\n\ 37161748Scperciva The Regents of the University of California. All rights reserved.\n"; 38161748Scperciva#endif /* not lint */ 39161748Scperciva 40161748Scperciva#if 0 41161748Scperciva#ifndef lint 42161748Scpercivastatic char sccsid[] = "@(#)msgs.c 8.2 (Berkeley) 4/28/95"; 43161748Scperciva#endif /* not lint */ 44161748Scperciva#endif 45161748Scperciva 46161748Scperciva#include <sys/cdefs.h> 47173564Scperciva__FBSDID("$FreeBSD: head/usr.bin/msgs/msgs.c 102084 2002-08-19 03:07:56Z jmallett $"); 48161748Scperciva 49161748Scperciva/* 50161748Scperciva * msgs - a user bulletin board program 51161748Scperciva * 52161748Scperciva * usage: 53161748Scperciva * msgs [fhlopq] [[-]number] to read messages 54161748Scperciva * msgs -s to place messages 55161748Scperciva * msgs -c [-days] to clean up the bulletin board 56173564Scperciva * 57173564Scperciva * prompt commands are: 58161748Scperciva * y print message 59181142Scperciva * n flush message, go to next message 60161748Scperciva * q flush message, quit 61161748Scperciva * p print message, turn on 'pipe thru more' mode 62161748Scperciva * P print message, turn off 'pipe thru more' mode 63161748Scperciva * - reprint last message 64161748Scperciva * s[-][<num>] [<filename>] save message 65161748Scperciva * m[-][<num>] mail with message in temp mbox 66161748Scperciva * x exit without flushing this message 67161748Scperciva * <num> print message number <num> 68161748Scperciva */ 69161748Scperciva 70161748Scperciva#define V7 /* will look for TERM in the environment */ 71161748Scperciva#define OBJECT /* will object to messages without Subjects */ 72161748Scperciva/* #define REJECT */ /* will reject messages without Subjects 73161748Scperciva (OBJECT must be defined also) */ 74161748Scperciva/* #define UNBUFFERED *//* use unbuffered output */ 75161748Scperciva 76161748Scperciva#include <sys/param.h> 77161748Scperciva#include <sys/stat.h> 78161748Scperciva#include <ctype.h> 79161748Scperciva#include <dirent.h> 80161748Scperciva#include <err.h> 81161748Scperciva#include <errno.h> 82161748Scperciva#include <fcntl.h> 83161748Scperciva#include <locale.h> 84161748Scperciva#include <pwd.h> 85161748Scperciva#include <setjmp.h> 86161748Scperciva#include <termcap.h> 87161748Scperciva#include <termios.h> 88161748Scperciva#include <signal.h> 89161748Scperciva#include <stdio.h> 90181142Scperciva#include <stdlib.h> 91196392Ssimon#include <string.h> 92161748Scperciva#include <time.h> 93161748Scperciva#include <unistd.h> 94161748Scperciva#include "pathnames.h" 95161748Scperciva 96161748Scperciva#define CMODE 0644 /* bounds file creation mode */ 97161748Scperciva#define NO 0 98161748Scperciva#define YES 1 99161748Scperciva#define SUPERUSER 0 /* superuser uid */ 100161748Scperciva#define DAEMON 1 /* daemon uid */ 101161748Scperciva#define NLINES 24 /* default number of lines/crt screen */ 102161748Scperciva#define NDAYS 21 /* default keep time for messages */ 103161748Scperciva#define DAYS *24*60*60 /* seconds/day */ 104161748Scperciva#define MSGSRC ".msgsrc" /* user's rc file */ 105161748Scperciva#define BOUNDS "bounds" /* message bounds file */ 106161748Scperciva#define NEXT "Next message? [yq]" 107161748Scperciva#define MORE "More? [ynq]" 108161748Scperciva#define NOMORE "(No more) [q] ?" 109161748Scperciva 110161748Scpercivatypedef char bool; 111161748Scperciva 112161748ScpercivaFILE *msgsrc; 113161748ScpercivaFILE *newmsg; 114161748Scpercivaconst char *sep = "-"; 115161748Scpercivachar inbuf[BUFSIZ]; 116161748Scpercivachar fname[MAXPATHLEN]; 117161748Scpercivachar cmdbuf[MAXPATHLEN + MAXPATHLEN]; 118161748Scpercivachar subj[128]; 119161748Scpercivachar from[128]; 120161748Scpercivachar date[128]; 121161748Scpercivachar *ptr; 122161748Scpercivachar *in; 123161748Scpercivabool local; 124161748Scpercivabool ruptible; 125161748Scpercivabool totty; 126161748Scpercivabool seenfrom; 127161748Scpercivabool seensubj; 128161748Scpercivabool blankline; 129161748Scpercivabool printing = NO; 130161748Scpercivabool mailing = NO; 131161748Scpercivabool quitit = NO; 132161748Scpercivabool sending = NO; 133161748Scpercivabool intrpflg = NO; 134161748Scpercivauid_t uid; 135161748Scpercivaint msg; 136161748Scpercivaint prevmsg; 137161748Scpercivaint lct; 138161748Scpercivaint nlines; 139161748Scpercivaint Lpp = 0; 140161748Scpercivatime_t t; 141161748Scpercivatime_t keep; 142161748Scperciva 143161748Scperciva/* option initialization */ 144161748Scpercivabool hdrs = NO; 145161748Scpercivabool qopt = NO; 146161748Scpercivabool hush = NO; 147161748Scpercivabool send_msg = NO; 148161748Scpercivabool locomode = NO; 149161748Scpercivabool use_pager = NO; 150161748Scpercivabool clean = NO; 151161748Scpercivabool lastcmd = NO; 152161748Scpercivajmp_buf tstpbuf; 153161748Scperciva 154161748Scpercivavoid ask(const char *); 155161748Scpercivavoid gfrsub(FILE *); 156161748Scpercivaint linecnt(FILE *); 157161748Scpercivaint next(char *); 158161748Scpercivachar *nxtfld(unsigned char *); 159161748Scpercivavoid onsusp(int); 160161748Scpercivavoid onintr(int); 161161748Scpercivavoid prmesg(int); 162161748Scpercivastatic void usage(void); 163161748Scperciva 164161748Scpercivaint 165161748Scpercivamain(argc, argv) 166161748Scpercivaint argc; char *argv[]; 167161748Scperciva{ 168161748Scperciva bool newrc, already; 169161748Scperciva int rcfirst = 0; /* first message to print (from .rc) */ 170161748Scperciva int rcback = 0; /* amount to back off of rcfirst */ 171161748Scperciva int firstmsg = 0, nextmsg = 0, lastmsg = 0; 172161748Scperciva int blast = 0; 173161748Scperciva struct stat buf; /* stat to check access of bounds */ 174161748Scperciva FILE *bounds; 175161748Scperciva 176161748Scperciva#ifdef UNBUFFERED 177161748Scperciva setbuf(stdout, NULL); 178161748Scperciva#endif 179161748Scperciva setlocale(LC_ALL, ""); 180161748Scperciva 181161748Scperciva time(&t); 182161748Scperciva setuid(uid = getuid()); 183161748Scperciva ruptible = (signal(SIGINT, SIG_IGN) == SIG_DFL); 184161748Scperciva if (ruptible) 185161748Scperciva signal(SIGINT, SIG_DFL); 186161748Scperciva 187161748Scperciva argc--, argv++; 188161748Scperciva while (argc > 0) { 189161748Scperciva if (isdigit(argv[0][0])) { /* starting message # */ 190161748Scperciva rcfirst = atoi(argv[0]); 191161748Scperciva } 192161748Scperciva else if (isdigit(argv[0][1])) { /* backward offset */ 193161748Scperciva rcback = atoi( &( argv[0][1] ) ); 194161748Scperciva } 195161748Scperciva else { 196161748Scperciva ptr = *argv; 197161748Scperciva while (*ptr) switch (*ptr++) { 198161748Scperciva 199161748Scperciva case '-': 200161748Scperciva break; 201161748Scperciva 202161748Scperciva case 'c': 203161748Scperciva if (uid != SUPERUSER && uid != DAEMON) 204161748Scperciva errx(1, 205161748Scperciva "only the super-user can use the c flag"); 206161748Scperciva clean = YES; 207161748Scperciva break; 208161748Scperciva 209161748Scperciva case 'f': /* silently */ 210161748Scperciva hush = YES; 211161748Scperciva break; 212161748Scperciva 213161748Scperciva case 'h': /* headers only */ 214161748Scperciva hdrs = YES; 215161748Scperciva break; 216161748Scperciva 217161748Scperciva case 'l': /* local msgs only */ 218161748Scperciva locomode = YES; 219161748Scperciva break; 220161748Scperciva 221161748Scperciva case 'o': /* option to save last message */ 222161748Scperciva lastcmd = YES; 223161748Scperciva break; 224161748Scperciva 225161748Scperciva case 'p': /* pipe thru 'more' during long msgs */ 226161748Scperciva use_pager = YES; 227181142Scperciva break; 228181142Scperciva 229181142Scperciva case 'q': /* query only */ 230181142Scperciva qopt = YES; 231181142Scperciva break; 232181142Scperciva 233181142Scperciva case 's': /* sending TO msgs */ 234161748Scperciva send_msg = YES; 235161748Scperciva break; 236161748Scperciva 237161748Scperciva default: 238161748Scperciva usage(); 239161748Scperciva } 240161748Scperciva } 241161748Scperciva argc--, argv++; 242173564Scperciva } 243173564Scperciva 244173564Scperciva /* 245173564Scperciva * determine current message bounds 246173564Scperciva */ 247173564Scperciva snprintf(fname, sizeof(fname), "%s/%s", _PATH_MSGS, BOUNDS); 248173564Scperciva 249173564Scperciva /* 250161748Scperciva * Test access rights to the bounds file 251161748Scperciva * This can be a little tricky. if(send_msg), then 252161748Scperciva * we will create it. We assume that if(send_msg), 253161748Scperciva * then you have write permission there. 254161748Scperciva * Else, it better be there, or we bail. 255161748Scperciva */ 256161748Scperciva if (send_msg != YES) { 257161748Scperciva if (stat(fname, &buf) < 0) { 258161748Scperciva if (hush != YES) { 259173564Scperciva err(errno, "%s", fname); 260173564Scperciva } else { 261173564Scperciva exit(1); 262173564Scperciva } 263173564Scperciva } 264173564Scperciva } 265173564Scperciva bounds = fopen(fname, "r"); 266173564Scperciva 267173564Scperciva if (bounds != NULL) { 268173564Scperciva fscanf(bounds, "%d %d\n", &firstmsg, &lastmsg); 269173564Scperciva fclose(bounds); 270173564Scperciva blast = lastmsg; /* save upper bound */ 271173564Scperciva } 272173564Scperciva 273173564Scperciva if (clean) 274173564Scperciva keep = t - (rcback? rcback : NDAYS) DAYS; 275173564Scperciva 276173564Scperciva if (clean || bounds == NULL) { /* relocate message bounds */ 277173564Scperciva struct dirent *dp; 278173564Scperciva struct stat stbuf; 279173564Scperciva bool seenany = NO; 280173564Scperciva DIR *dirp; 281173564Scperciva 282173564Scperciva dirp = opendir(_PATH_MSGS); 283173564Scperciva if (dirp == NULL) 284173564Scperciva err(errno, "%s", _PATH_MSGS); 285173564Scperciva 286173564Scperciva firstmsg = 32767; 287197618Scperciva lastmsg = 0; 288197618Scperciva 289197618Scperciva for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)){ 290173564Scperciva register char *cp = dp->d_name; 291173564Scperciva register int i = 0; 292161748Scperciva 293161748Scperciva if (dp->d_ino == 0) 294161748Scperciva continue; 295161748Scperciva if (dp->d_namlen == 0) 296161748Scperciva continue; 297161748Scperciva 298161748Scperciva if (clean) 299161748Scperciva snprintf(inbuf, sizeof(inbuf), "%s/%s", _PATH_MSGS, cp); 300161748Scperciva 301161748Scperciva while (isdigit(*cp)) 302161748Scperciva i = i * 10 + *cp++ - '0'; 303161748Scperciva if (*cp) 304161748Scperciva continue; /* not a message! */ 305161748Scperciva 306161748Scperciva if (clean) { 307161748Scperciva if (stat(inbuf, &stbuf) != 0) 308161748Scperciva continue; 309161748Scperciva if (stbuf.st_mtime < keep 310161748Scperciva && stbuf.st_mode&S_IWRITE) { 311161748Scperciva unlink(inbuf); 312161748Scperciva continue; 313161748Scperciva } 314196392Ssimon } 315196392Ssimon 316196392Ssimon if (i > lastmsg) 317196392Ssimon lastmsg = i; 318196392Ssimon if (i < firstmsg) 319196392Ssimon firstmsg = i; 320196392Ssimon seenany = YES; 321196392Ssimon } 322196392Ssimon closedir(dirp); 323196392Ssimon 324196392Ssimon if (!seenany) { 325196392Ssimon if (blast != 0) /* never lower the upper bound! */ 326196392Ssimon lastmsg = blast; 327196392Ssimon firstmsg = lastmsg + 1; 328196392Ssimon } 329196392Ssimon else if (blast > lastmsg) 330196392Ssimon lastmsg = blast; 331196392Ssimon 332196392Ssimon if (!send_msg) { 333196392Ssimon bounds = fopen(fname, "w"); 334196392Ssimon if (bounds == NULL) 335196392Ssimon err(errno, "%s", fname); 336196392Ssimon chmod(fname, CMODE); 337196392Ssimon fprintf(bounds, "%d %d\n", firstmsg, lastmsg); 338196392Ssimon fclose(bounds); 339196392Ssimon } 340196392Ssimon } 341196392Ssimon 342196392Ssimon if (send_msg) { 343196392Ssimon /* 344196392Ssimon * Send mode - place msgs in _PATH_MSGS 345196392Ssimon */ 346196392Ssimon bounds = fopen(fname, "w"); 347196392Ssimon if (bounds == NULL) 348196392Ssimon err(errno, "%s", fname); 349196392Ssimon 350196392Ssimon nextmsg = lastmsg + 1; 351196392Ssimon snprintf(fname, sizeof(fname), "%s/%d", _PATH_MSGS, nextmsg); 352196392Ssimon newmsg = fopen(fname, "w"); 353196392Ssimon if (newmsg == NULL) 354196392Ssimon err(errno, "%s", fname); 355196392Ssimon chmod(fname, CMODE); 356196392Ssimon 357196392Ssimon fprintf(bounds, "%d %d\n", firstmsg, nextmsg); 358196392Ssimon fclose(bounds); 359196392Ssimon 360196392Ssimon sending = YES; 361196392Ssimon if (ruptible) 362196392Ssimon signal(SIGINT, onintr); 363196392Ssimon 364196392Ssimon if (isatty(fileno(stdin))) { 365196392Ssimon ptr = getpwuid(uid)->pw_name; 366196392Ssimon printf("Message %d:\nFrom %s %sSubject: ", 367196392Ssimon nextmsg, ptr, ctime(&t)); 368196392Ssimon fflush(stdout); 369196392Ssimon fgets(inbuf, sizeof inbuf, stdin); 370196392Ssimon putchar('\n'); 371196392Ssimon fflush(stdout); 372196392Ssimon fprintf(newmsg, "From %s %sSubject: %s\n", 373196392Ssimon ptr, ctime(&t), inbuf); 374196392Ssimon blankline = seensubj = YES; 375196392Ssimon } 376196392Ssimon else 377196392Ssimon blankline = seensubj = NO; 378161748Scperciva for (;;) { 379161748Scperciva fgets(inbuf, sizeof inbuf, stdin); 380161748Scperciva if (feof(stdin) || ferror(stdin)) 381161748Scperciva break; 382161748Scperciva blankline = (blankline || (inbuf[0] == '\n')); 383161748Scperciva seensubj = (seensubj || (!blankline && (strncmp(inbuf, "Subj", 4) == 0))); 384161748Scperciva fputs(inbuf, newmsg); 385161748Scperciva } 386161748Scperciva#ifdef OBJECT 387161748Scperciva if (!seensubj) { 388161748Scperciva printf("NOTICE: Messages should have a Subject field!\n"); 389161748Scperciva#ifdef REJECT 390161748Scperciva unlink(fname); 391161748Scperciva#endif 392161748Scperciva exit(1); 393161748Scperciva } 394161748Scperciva#endif 395161748Scperciva exit(ferror(stdin)); 396161748Scperciva } 397161748Scperciva if (clean) 398161748Scperciva exit(0); 399161748Scperciva 400161748Scperciva /* 401161748Scperciva * prepare to display messages 402161748Scperciva */ 403161748Scperciva totty = (isatty(fileno(stdout)) != 0); 404161748Scperciva use_pager = use_pager && totty; 405161748Scperciva 406161748Scperciva snprintf(fname, sizeof(fname), "%s/%s", getenv("HOME"), MSGSRC); 407161748Scperciva msgsrc = fopen(fname, "r"); 408161748Scperciva if (msgsrc) { 409161748Scperciva newrc = NO; 410161748Scperciva fscanf(msgsrc, "%d\n", &nextmsg); 411161748Scperciva fclose(msgsrc); 412161748Scperciva if (nextmsg > lastmsg+1) { 413161748Scperciva printf("Warning: bounds have been reset (%d, %d)\n", 414161748Scperciva firstmsg, lastmsg); 415161748Scperciva truncate(fname, (off_t)0); 416161748Scperciva newrc = YES; 417161748Scperciva } 418161748Scperciva else if (!rcfirst) 419161748Scperciva rcfirst = nextmsg - rcback; 420161748Scperciva } 421161748Scperciva else 422161748Scperciva newrc = YES; 423161748Scperciva msgsrc = fopen(fname, "r+"); 424161748Scperciva if (msgsrc == NULL) 425161748Scperciva msgsrc = fopen(fname, "w"); 426161748Scperciva if (msgsrc == NULL) 427161748Scperciva err(errno, "%s", fname); 428161748Scperciva if (rcfirst) { 429161748Scperciva if (rcfirst > lastmsg+1) { 430161748Scperciva printf("Warning: the last message is number %d.\n", 431161748Scperciva lastmsg); 432173564Scperciva rcfirst = nextmsg; 433173564Scperciva } 434173564Scperciva if (rcfirst > firstmsg) 435173564Scperciva firstmsg = rcfirst; /* don't set below first msg */ 436161748Scperciva } 437161748Scperciva if (newrc) { 438161748Scperciva nextmsg = firstmsg; 439161748Scperciva rewind(msgsrc); 440161748Scperciva fprintf(msgsrc, "%d\n", nextmsg); 441161748Scperciva fflush(msgsrc); 442161748Scperciva } 443161748Scperciva 444161748Scperciva#ifdef V7 445161748Scperciva if (totty) { 446161748Scperciva struct winsize win; 447161748Scperciva if (ioctl(fileno(stdout), TIOCGWINSZ, &win) != -1) 448161748Scperciva Lpp = win.ws_row; 449161748Scperciva if (Lpp <= 0) { 450161748Scperciva if (tgetent(inbuf, getenv("TERM")) <= 0 451161748Scperciva || (Lpp = tgetnum("li")) <= 0) { 452161748Scperciva Lpp = NLINES; 453161748Scperciva } 454181142Scperciva } 455161748Scperciva } 456161748Scperciva#endif 457161748Scperciva Lpp -= 6; /* for headers, etc. */ 458161748Scperciva 459161748Scperciva already = NO; 460161748Scperciva prevmsg = firstmsg; 461161748Scperciva printing = YES; 462161748Scperciva if (ruptible) 463161748Scperciva signal(SIGINT, onintr); 464161748Scperciva 465161748Scperciva /* 466161748Scperciva * Main program loop 467161748Scperciva */ 468161748Scperciva for (msg = firstmsg; msg <= lastmsg; msg++) { 469161748Scperciva 470161748Scperciva snprintf(fname, sizeof(fname), "%s/%d", _PATH_MSGS, msg); 471161748Scperciva newmsg = fopen(fname, "r"); 472161748Scperciva if (newmsg == NULL) 473161748Scperciva continue; 474161748Scperciva 475161748Scperciva gfrsub(newmsg); /* get From and Subject fields */ 476161748Scperciva if (locomode && !local) { 477161748Scperciva fclose(newmsg); 478161748Scperciva continue; 479161748Scperciva } 480161748Scperciva 481161748Scperciva if (qopt) { /* This has to be located here */ 482161748Scperciva printf("There are new messages.\n"); 483161748Scperciva exit(0); 484161748Scperciva } 485161748Scperciva 486161748Scperciva if (already && !hdrs) 487161748Scperciva putchar('\n'); 488161748Scperciva 489161748Scperciva /* 490161748Scperciva * Print header 491161748Scperciva */ 492161748Scperciva if (totty) 493161748Scperciva signal(SIGTSTP, onsusp); 494161748Scperciva (void) setjmp(tstpbuf); 495161748Scperciva already = YES; 496161748Scperciva nlines = 2; 497161748Scperciva if (seenfrom) { 498161748Scperciva printf("Message %d:\nFrom %s %s", msg, from, date); 499161748Scperciva nlines++; 500161748Scperciva } 501161748Scperciva if (seensubj) { 502161748Scperciva printf("Subject: %s", subj); 503161748Scperciva nlines++; 504161748Scperciva } 505161748Scperciva else { 506161748Scperciva if (seenfrom) { 507161748Scperciva putchar('\n'); 508161748Scperciva nlines++; 509161748Scperciva } 510161748Scperciva while (nlines < 6 511161748Scperciva && fgets(inbuf, sizeof inbuf, newmsg) 512161748Scperciva && inbuf[0] != '\n') { 513161748Scperciva fputs(inbuf, stdout); 514161748Scperciva nlines++; 515161748Scperciva } 516161748Scperciva } 517161748Scperciva 518161748Scperciva lct = linecnt(newmsg); 519161748Scperciva if (lct) 520161748Scperciva printf("(%d%slines) ", lct, seensubj? " " : " more "); 521161748Scperciva 522161748Scperciva if (hdrs) { 523161748Scperciva printf("\n-----\n"); 524161748Scperciva fclose(newmsg); 525161748Scperciva continue; 526161748Scperciva } 527161748Scperciva 528161748Scperciva /* 529161748Scperciva * Ask user for command 530173564Scperciva */ 531196392Ssimon if (totty) 532196392Ssimon ask(lct? MORE : (msg==lastmsg? NOMORE : NEXT)); 533196392Ssimon else 534161748Scperciva inbuf[0] = 'y'; 535161748Scperciva if (totty) 536161748Scperciva signal(SIGTSTP, SIG_DFL); 537161748Scpercivacmnd: 538161748Scperciva in = inbuf; 539161748Scperciva switch (*in) { 540161748Scperciva case 'x': 541161748Scperciva /* FALLTHROUGH */ 542161748Scperciva case 'X': 543161748Scperciva exit(0); 544161748Scperciva /* NOTREACHED */ 545161748Scperciva 546161748Scperciva case 'q': 547161748Scperciva /* FALLTHROUGH */ 548161748Scperciva case 'Q': 549161748Scperciva quitit = YES; 550161748Scperciva printf("--Postponed--\n"); 551161748Scperciva exit(0); 552161748Scperciva /* NOTREACHED */ 553161748Scperciva 554161748Scperciva case 'n': 555161748Scperciva /* FALLTHROUGH */ 556161748Scperciva case 'N': 557161748Scperciva if (msg >= nextmsg) sep = "Flushed"; 558161748Scperciva prevmsg = msg; 559161748Scperciva break; 560161748Scperciva 561161748Scperciva case 'p': 562161748Scperciva /* FALLTHROUGH */ 563161748Scperciva case 'P': 564161748Scperciva use_pager = (*in++ == 'p'); 565161748Scperciva /* FALLTHROUGH */ 566161748Scperciva case '\n': 567161748Scperciva /* FALLTHROUGH */ 568161748Scperciva case 'y': 569161748Scperciva default: 570161748Scperciva if (*in == '-') { 571161748Scperciva msg = prevmsg-1; 572161748Scperciva sep = "replay"; 573161748Scperciva break; 574161748Scperciva } 575212434Scperciva if (isdigit(*in)) { 576161748Scperciva msg = next(in); 577161748Scperciva sep = in; 578161748Scperciva break; 579161748Scperciva } 580161748Scperciva 581161748Scperciva prmesg(nlines + lct + (seensubj? 1 : 0)); 582161748Scperciva prevmsg = msg; 583161748Scperciva 584161748Scperciva } 585161748Scperciva 586161748Scperciva printf("--%s--\n", sep); 587161748Scperciva sep = "-"; 588161748Scperciva if (msg >= nextmsg) { 589161748Scperciva nextmsg = msg + 1; 590161748Scperciva rewind(msgsrc); 591161748Scperciva fprintf(msgsrc, "%d\n", nextmsg); 592161748Scperciva fflush(msgsrc); 593161748Scperciva } 594161748Scperciva if (newmsg) 595161748Scperciva fclose(newmsg); 596161748Scperciva if (quitit) 597161748Scperciva break; 598161748Scperciva } 599161748Scperciva 600161748Scperciva /* 601161748Scperciva * Make sure .rc file gets updated 602161748Scperciva */ 603161748Scperciva if (--msg >= nextmsg) { 604161748Scperciva nextmsg = msg + 1; 605161748Scperciva rewind(msgsrc); 606200054Scperciva fprintf(msgsrc, "%d\n", nextmsg); 607161748Scperciva fflush(msgsrc); 608161748Scperciva } 609161748Scperciva if (already && !quitit && lastcmd && totty) { 610161748Scperciva /* 611161748Scperciva * save or reply to last message? 612161748Scperciva */ 613161748Scperciva msg = prevmsg; 614161748Scperciva ask(NOMORE); 615161748Scperciva if (inbuf[0] == '-' || isdigit(inbuf[0])) 616161748Scperciva goto cmnd; 617161748Scperciva } 618173564Scperciva if (!(already || hush || qopt)) 619161748Scperciva printf("No new messages.\n"); 620161748Scperciva exit(0); 621161748Scperciva /* NOTREACHED */ 622161748Scperciva} 623161748Scperciva 624161748Scpercivastatic void 625161748Scpercivausage() 626161748Scperciva{ 627161748Scperciva fprintf(stderr, "usage: msgs [fhlopq] [[-]number]\n"); 628167189Scperciva exit(1); 629167189Scperciva} 630167189Scperciva 631167189Scpercivavoid 632167189Scpercivaprmesg(length) 633167189Scpercivaint length; 634167189Scperciva{ 635167189Scperciva FILE *outf; 636167189Scperciva char *env_pager; 637167189Scperciva 638167189Scperciva if (use_pager && length > Lpp) { 639167189Scperciva signal(SIGPIPE, SIG_IGN); 640167189Scperciva signal(SIGQUIT, SIG_IGN); 641167189Scperciva if ((env_pager = getenv("PAGER")) == NULL) { 642167189Scperciva snprintf(cmdbuf, sizeof(cmdbuf), _PATH_PAGER, Lpp); 643167189Scperciva } else { 644167189Scperciva snprintf(cmdbuf, sizeof(cmdbuf), "%s", env_pager); 645167189Scperciva } 646161748Scperciva outf = popen(cmdbuf, "w"); 647161748Scperciva if (!outf) 648161748Scperciva outf = stdout; 649161748Scperciva else 650161748Scperciva setbuf(outf, (char *)NULL); 651161748Scperciva } 652161748Scperciva else 653161748Scperciva outf = stdout; 654161748Scperciva 655161748Scperciva if (seensubj) 656161748Scperciva putc('\n', outf); 657161748Scperciva 658212434Scperciva while (fgets(inbuf, sizeof inbuf, newmsg)) { 659212434Scperciva fputs(inbuf, outf); 660212434Scperciva if (ferror(outf)) { 661212434Scperciva clearerr(outf); 662212434Scperciva break; 663212434Scperciva } 664212434Scperciva } 665212434Scperciva 666212434Scperciva if (outf != stdout) { 667212434Scperciva pclose(outf); 668212434Scperciva signal(SIGPIPE, SIG_DFL); 669212434Scperciva signal(SIGQUIT, SIG_DFL); 670173564Scperciva } 671173564Scperciva else { 672212434Scperciva fflush(stdout); 673173564Scperciva } 674173564Scperciva 675173564Scperciva /* force wait on output */ 676173564Scperciva tcdrain(fileno(stdout)); 677173564Scperciva} 678173564Scperciva 679173564Scpercivavoid 680173564Scpercivaonintr(unused) 681173564Scperciva int unused __unused; 682173564Scperciva{ 683173564Scperciva signal(SIGINT, onintr); 684173564Scperciva if (mailing) 685173564Scperciva unlink(fname); 686173564Scperciva if (sending) { 687173564Scperciva unlink(fname); 688173564Scperciva puts("--Killed--"); 689173564Scperciva exit(1); 690173564Scperciva } 691173564Scperciva if (printing) { 692173564Scperciva putchar('\n'); 693173564Scperciva if (hdrs) 694173564Scperciva exit(0); 695173564Scperciva sep = "Interrupt"; 696173564Scperciva if (newmsg) 697173564Scperciva fseeko(newmsg, (off_t)0, SEEK_END); 698173564Scperciva intrpflg = YES; 699173564Scperciva } 700173564Scperciva} 701173564Scperciva 702173564Scperciva/* 703173564Scperciva * We have just gotten a susp. Suspend and prepare to resume. 704173564Scperciva */ 705173564Scpercivavoid 706173564Scpercivaonsusp(unused) 707173564Scperciva int unused __unused; 708173564Scperciva{ 709173564Scperciva signal(SIGTSTP, SIG_DFL); 710161748Scperciva sigsetmask(0); 711161748Scperciva kill(0, SIGTSTP); 712161748Scperciva signal(SIGTSTP, onsusp); 713161748Scperciva if (!mailing) 714161748Scperciva longjmp(tstpbuf, 0); 715161748Scperciva} 716161748Scperciva 717161748Scpercivaint 718161748Scpercivalinecnt(f) 719173441ScpercivaFILE *f; 720173441Scperciva{ 721173441Scperciva off_t oldpos = ftello(f); 722173441Scperciva int l = 0; 723173441Scperciva char lbuf[BUFSIZ]; 724173441Scperciva 725173441Scperciva while (fgets(lbuf, sizeof lbuf, f)) 726161748Scperciva l++; 727161748Scperciva clearerr(f); 728161748Scperciva fseeko(f, oldpos, SEEK_SET); 729161748Scperciva return (l); 730161748Scperciva} 731161748Scperciva 732161748Scpercivaint 733161748Scpercivanext(buf) 734161748Scpercivachar *buf; 735161748Scperciva{ 736161748Scperciva int i; 737161748Scperciva sscanf(buf, "%d", &i); 738161748Scperciva sprintf(buf, "Goto %d", i); 739161748Scperciva return(--i); 740161748Scperciva} 741161748Scperciva 742161748Scpercivavoid 743161748Scpercivaask(prompt) 744161748Scpercivaconst char *prompt; 745161748Scperciva{ 746161748Scperciva char inch; 747161748Scperciva int n, cmsg, fd; 748161748Scperciva off_t oldpos; 749161748Scperciva FILE *cpfrom, *cpto; 750161748Scperciva 751196392Ssimon printf("%s ", prompt); 752196392Ssimon fflush(stdout); 753196392Ssimon intrpflg = NO; 754196392Ssimon (void) fgets(inbuf, sizeof inbuf, stdin); 755196392Ssimon if ((n = strlen(inbuf)) > 0 && inbuf[n - 1] == '\n') 756196392Ssimon inbuf[n - 1] = '\0'; 757196392Ssimon if (intrpflg) 758196392Ssimon inbuf[0] = 'x'; 759161748Scperciva 760161748Scperciva /* 761161748Scperciva * Handle 'mail' and 'save' here. 762161748Scperciva */ 763161748Scperciva if ((inch = inbuf[0]) == 's' || inch == 'm') { 764161748Scperciva if (inbuf[1] == '-') 765161748Scperciva cmsg = prevmsg; 766161748Scperciva else if (isdigit(inbuf[1])) 767161748Scperciva cmsg = atoi(&inbuf[1]); 768161748Scperciva else 769161748Scperciva cmsg = msg; 770161748Scperciva snprintf(fname, sizeof(fname), "%s/%d", _PATH_MSGS, cmsg); 771161748Scperciva 772161748Scperciva oldpos = ftello(newmsg); 773161748Scperciva 774161748Scperciva cpfrom = fopen(fname, "r"); 775161748Scperciva if (!cpfrom) { 776161748Scperciva printf("Message %d not found\n", cmsg); 777161748Scperciva ask (prompt); 778161748Scperciva return; 779161748Scperciva } 780161748Scperciva 781161748Scperciva if (inch == 's') { 782161748Scperciva in = nxtfld(inbuf); 783161748Scperciva if (*in) { 784161748Scperciva for (n=0; in[n] > ' '; n++) { /* sizeof fname? */ 785161748Scperciva fname[n] = in[n]; 786161748Scperciva } 787161748Scperciva fname[n] = NULL; 788161748Scperciva } 789161748Scperciva else 790161748Scperciva strcpy(fname, "Messages"); 791161748Scperciva fd = open(fname, O_RDWR|O_EXCL|O_CREAT|O_APPEND); 792161748Scperciva } 793161748Scperciva else { 794161748Scperciva strcpy(fname, _PATH_TMP); 795181142Scperciva fd = mkstemp(fname); 796181142Scperciva if (fd != -1) { 797181142Scperciva snprintf(cmdbuf, sizeof(cmdbuf), _PATH_MAIL, 798181142Scperciva fname); 799181142Scperciva mailing = YES; 800181142Scperciva } 801181142Scperciva } 802181142Scperciva if (fd == -1 || (cpto = fdopen(fd, "a")) == NULL) { 803181142Scperciva if (fd != -1) 804181142Scperciva close(fd); 805181142Scperciva warn("%s", fname); 806181142Scperciva mailing = NO; 807181142Scperciva fseeko(newmsg, oldpos, SEEK_SET); 808181142Scperciva ask(prompt); 809181142Scperciva return; 810181142Scperciva } 811181142Scperciva 812181142Scperciva while ((n = fread(inbuf, 1, sizeof inbuf, cpfrom))) 813181142Scperciva fwrite(inbuf, 1, n, cpto); 814181142Scperciva 815181142Scperciva fclose(cpfrom); 816181142Scperciva fclose(cpto); 817181142Scperciva fseeko(newmsg, oldpos, SEEK_SET);/* reposition current message */ 818181142Scperciva if (inch == 's') 819181142Scperciva printf("Message %d saved in \"%s\"\n", cmsg, fname); 820181142Scperciva else { 821181142Scperciva system(cmdbuf); 822181142Scperciva unlink(fname); 823181142Scperciva mailing = NO; 824181142Scperciva } 825181142Scperciva ask(prompt); 826181142Scperciva } 827181142Scperciva} 828181142Scperciva 829181142Scpercivavoid 830181142Scpercivagfrsub(infile) 831181142ScpercivaFILE *infile; 832181142Scperciva{ 833181142Scperciva off_t frompos; 834181142Scperciva int count; 835181142Scperciva 836181142Scperciva seensubj = seenfrom = NO; 837181142Scperciva local = YES; 838181142Scperciva subj[0] = from[0] = date[0] = NULL; 839181142Scperciva 840181142Scperciva /* 841181142Scperciva * Is this a normal message? 842181142Scperciva */ 843181142Scperciva if (fgets(inbuf, sizeof inbuf, infile)) { 844181142Scperciva if (strncmp(inbuf, "From", 4)==0) { 845181142Scperciva /* 846181142Scperciva * expected form starts with From 847181142Scperciva */ 848181142Scperciva seenfrom = YES; 849181142Scperciva frompos = ftello(infile); 850181142Scperciva ptr = from; 851181142Scperciva in = nxtfld(inbuf); 852181142Scperciva if (*in) { 853181142Scperciva count = sizeof(from) - 1; 854181142Scperciva while (*in && *in > ' ' && count-- > 0) { 855181142Scperciva if (*in == ':' || *in == '@' || 856181142Scperciva *in == '!') 857181142Scperciva local = NO; 858181142Scperciva *ptr++ = *in++; 859181142Scperciva } 860181142Scperciva } 861181142Scperciva *ptr = NULL; 862181142Scperciva if (*(in = nxtfld(in))) 863181142Scperciva strncpy(date, in, sizeof date); 864181142Scperciva else { 865181142Scperciva date[0] = '\n'; 866181142Scperciva date[1] = NULL; 867181142Scperciva } 868181142Scperciva } 869181142Scperciva else { 870181142Scperciva /* 871181142Scperciva * not the expected form 872181142Scperciva */ 873181142Scperciva rewind(infile); 874181142Scperciva return; 875181142Scperciva } 876181142Scperciva } 877181142Scperciva else 878181142Scperciva /* 879181142Scperciva * empty file ? 880161748Scperciva */ 881161748Scperciva return; 882161748Scperciva 883161748Scperciva /* 884161748Scperciva * look for Subject line until EOF or a blank line 885161748Scperciva */ 886161748Scperciva while (fgets(inbuf, sizeof inbuf, infile) 887161748Scperciva && !(blankline = (inbuf[0] == '\n'))) { 888161748Scperciva /* 889161748Scperciva * extract Subject line 890161748Scperciva */ 891161748Scperciva if (!seensubj && strncmp(inbuf, "Subj", 4)==0) { 892161748Scperciva seensubj = YES; 893161748Scperciva frompos = ftello(infile); 894161748Scperciva strncpy(subj, nxtfld(inbuf), sizeof subj); 895161748Scperciva } 896161748Scperciva } 897161748Scperciva if (!blankline) 898161748Scperciva /* 899161748Scperciva * ran into EOF 900161748Scperciva */ 901161748Scperciva fseeko(infile, frompos, SEEK_SET); 902161748Scperciva 903161748Scperciva if (!seensubj) 904161748Scperciva /* 905161748Scperciva * for possible use with Mail 906161748Scperciva */ 907161748Scperciva strncpy(subj, "(No Subject)\n", sizeof subj); 908161748Scperciva} 909161748Scperciva 910161748Scpercivachar * 911161748Scpercivanxtfld(s) 912161748Scpercivaunsigned char *s; 913161748Scperciva{ 914161748Scperciva if (*s) while (*s && !isspace(*s)) s++; /* skip over this field */ 915161748Scperciva if (*s) while (*s && isspace(*s)) s++; /* find start of next field */ 916161748Scperciva return (s); 917161748Scperciva} 918161748Scperciva