msgs.c revision 102944
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 46282870Sdelphij#include <sys/cdefs.h> 47161748Scperciva__FBSDID("$FreeBSD: head/usr.bin/msgs/msgs.c 102944 2002-09-04 23:29:10Z dwmalone $"); 48173564Scperciva 49161748Scperciva/* 50161748Scperciva * msgs - a user bulletin board program 51161748Scperciva * 52161748Scperciva * usage: 53282870Sdelphij * msgs [fhlopq] [[-]number] to read messages 54282870Sdelphij * msgs -s to place messages 55161748Scperciva * msgs -c [-days] to clean up the bulletin board 56161748Scperciva * 57161748Scperciva * prompt commands are: 58161748Scperciva * y print message 59173564Scperciva * n flush message, go to next message 60173564Scperciva * q flush message, quit 61161748Scperciva * p print message, turn on 'pipe thru more' mode 62181142Scperciva * 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> 90161748Scperciva#include <stdlib.h> 91161748Scperciva#include <string.h> 92161748Scperciva#include <time.h> 93181142Scperciva#include <unistd.h> 94196392Ssimon#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(int argc, char *argv[]) 166161748Scperciva{ 167161748Scperciva bool newrc, already; 168161748Scperciva int rcfirst = 0; /* first message to print (from .rc) */ 169161748Scperciva int rcback = 0; /* amount to back off of rcfirst */ 170161748Scperciva int firstmsg = 0, nextmsg = 0, lastmsg = 0; 171161748Scperciva int blast = 0; 172161748Scperciva struct stat buf; /* stat to check access of bounds */ 173161748Scperciva FILE *bounds; 174161748Scperciva 175161748Scperciva#ifdef UNBUFFERED 176161748Scperciva setbuf(stdout, NULL); 177161748Scperciva#endif 178161748Scperciva setlocale(LC_ALL, ""); 179161748Scperciva 180161748Scperciva time(&t); 181161748Scperciva setuid(uid = getuid()); 182161748Scperciva ruptible = (signal(SIGINT, SIG_IGN) == SIG_DFL); 183161748Scperciva if (ruptible) 184161748Scperciva signal(SIGINT, SIG_DFL); 185161748Scperciva 186161748Scperciva argc--, argv++; 187161748Scperciva while (argc > 0) { 188161748Scperciva if (isdigit(argv[0][0])) { /* starting message # */ 189161748Scperciva rcfirst = atoi(argv[0]); 190161748Scperciva } 191161748Scperciva else if (isdigit(argv[0][1])) { /* backward offset */ 192161748Scperciva rcback = atoi( &( argv[0][1] ) ); 193161748Scperciva } 194161748Scperciva else { 195161748Scperciva ptr = *argv; 196161748Scperciva while (*ptr) switch (*ptr++) { 197161748Scperciva 198161748Scperciva case '-': 199161748Scperciva break; 200161748Scperciva 201161748Scperciva case 'c': 202161748Scperciva if (uid != SUPERUSER && uid != DAEMON) 203161748Scperciva errx(1, 204161748Scperciva "only the super-user can use the c flag"); 205161748Scperciva clean = YES; 206161748Scperciva break; 207161748Scperciva 208161748Scperciva case 'f': /* silently */ 209161748Scperciva hush = YES; 210161748Scperciva break; 211161748Scperciva 212161748Scperciva case 'h': /* headers only */ 213161748Scperciva hdrs = YES; 214161748Scperciva break; 215161748Scperciva 216161748Scperciva case 'l': /* local msgs only */ 217161748Scperciva locomode = YES; 218161748Scperciva break; 219284936Sdelphij 220284936Sdelphij case 'o': /* option to save last message */ 221284936Sdelphij lastcmd = YES; 222284936Sdelphij break; 223284936Sdelphij 224284936Sdelphij case 'p': /* pipe thru 'more' during long msgs */ 225284936Sdelphij use_pager = YES; 226284936Sdelphij break; 227284936Sdelphij 228161748Scperciva case 'q': /* query only */ 229161748Scperciva qopt = YES; 230161748Scperciva break; 231161748Scperciva 232161748Scperciva case 's': /* sending TO msgs */ 233161748Scperciva send_msg = YES; 234161748Scperciva break; 235161748Scperciva 236161748Scperciva default: 237161748Scperciva usage(); 238181142Scperciva } 239181142Scperciva } 240181142Scperciva argc--, argv++; 241181142Scperciva } 242181142Scperciva 243181142Scperciva /* 244181142Scperciva * determine current message bounds 245161748Scperciva */ 246161748Scperciva snprintf(fname, sizeof(fname), "%s/%s", _PATH_MSGS, BOUNDS); 247161748Scperciva 248161748Scperciva /* 249161748Scperciva * Test access rights to the bounds file 250161748Scperciva * This can be a little tricky. if(send_msg), then 251161748Scperciva * we will create it. We assume that if(send_msg), 252161748Scperciva * then you have write permission there. 253173564Scperciva * Else, it better be there, or we bail. 254173564Scperciva */ 255173564Scperciva if (send_msg != YES) { 256173564Scperciva if (stat(fname, &buf) < 0) { 257173564Scperciva if (hush != YES) { 258173564Scperciva err(errno, "%s", fname); 259173564Scperciva } else { 260173564Scperciva exit(1); 261161748Scperciva } 262161748Scperciva } 263161748Scperciva } 264161748Scperciva bounds = fopen(fname, "r"); 265161748Scperciva 266161748Scperciva if (bounds != NULL) { 267161748Scperciva fscanf(bounds, "%d %d\n", &firstmsg, &lastmsg); 268161748Scperciva fclose(bounds); 269161748Scperciva blast = lastmsg; /* save upper bound */ 270173564Scperciva } 271173564Scperciva 272173564Scperciva if (clean) 273173564Scperciva keep = t - (rcback? rcback : NDAYS) DAYS; 274173564Scperciva 275173564Scperciva if (clean || bounds == NULL) { /* relocate message bounds */ 276173564Scperciva struct dirent *dp; 277173564Scperciva struct stat stbuf; 278173564Scperciva bool seenany = NO; 279173564Scperciva DIR *dirp; 280173564Scperciva 281173564Scperciva dirp = opendir(_PATH_MSGS); 282173564Scperciva if (dirp == NULL) 283173564Scperciva err(errno, "%s", _PATH_MSGS); 284173564Scperciva 285173564Scperciva firstmsg = 32767; 286173564Scperciva lastmsg = 0; 287173564Scperciva 288173564Scperciva for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)){ 289173564Scperciva char *cp = dp->d_name; 290173564Scperciva int i = 0; 291173564Scperciva 292173564Scperciva if (dp->d_ino == 0) 293173564Scperciva continue; 294173564Scperciva if (dp->d_namlen == 0) 295173564Scperciva continue; 296173564Scperciva 297173564Scperciva if (clean) 298197618Scperciva snprintf(inbuf, sizeof(inbuf), "%s/%s", _PATH_MSGS, cp); 299197618Scperciva 300197618Scperciva while (isdigit(*cp)) 301173564Scperciva i = i * 10 + *cp++ - '0'; 302173564Scperciva if (*cp) 303161748Scperciva continue; /* not a message! */ 304161748Scperciva 305161748Scperciva if (clean) { 306161748Scperciva if (stat(inbuf, &stbuf) != 0) 307161748Scperciva continue; 308161748Scperciva if (stbuf.st_mtime < keep 309161748Scperciva && stbuf.st_mode&S_IWRITE) { 310161748Scperciva unlink(inbuf); 311161748Scperciva continue; 312161748Scperciva } 313161748Scperciva } 314161748Scperciva 315161748Scperciva if (i > lastmsg) 316161748Scperciva lastmsg = i; 317161748Scperciva if (i < firstmsg) 318161748Scperciva firstmsg = i; 319161748Scperciva seenany = YES; 320161748Scperciva } 321161748Scperciva closedir(dirp); 322161748Scperciva 323161748Scperciva if (!seenany) { 324161748Scperciva if (blast != 0) /* never lower the upper bound! */ 325196392Ssimon lastmsg = blast; 326196392Ssimon firstmsg = lastmsg + 1; 327196392Ssimon } 328196392Ssimon else if (blast > lastmsg) 329196392Ssimon lastmsg = blast; 330196392Ssimon 331196392Ssimon if (!send_msg) { 332196392Ssimon bounds = fopen(fname, "w"); 333196392Ssimon if (bounds == NULL) 334196392Ssimon err(errno, "%s", fname); 335196392Ssimon chmod(fname, CMODE); 336196392Ssimon fprintf(bounds, "%d %d\n", firstmsg, lastmsg); 337196392Ssimon fclose(bounds); 338196392Ssimon } 339196392Ssimon } 340196392Ssimon 341196392Ssimon if (send_msg) { 342196392Ssimon /* 343196392Ssimon * Send mode - place msgs in _PATH_MSGS 344196392Ssimon */ 345196392Ssimon bounds = fopen(fname, "w"); 346196392Ssimon if (bounds == NULL) 347196392Ssimon err(errno, "%s", fname); 348196392Ssimon 349196392Ssimon nextmsg = lastmsg + 1; 350196392Ssimon snprintf(fname, sizeof(fname), "%s/%d", _PATH_MSGS, nextmsg); 351196392Ssimon newmsg = fopen(fname, "w"); 352196392Ssimon if (newmsg == NULL) 353196392Ssimon err(errno, "%s", fname); 354196392Ssimon chmod(fname, CMODE); 355196392Ssimon 356196392Ssimon fprintf(bounds, "%d %d\n", firstmsg, nextmsg); 357196392Ssimon fclose(bounds); 358196392Ssimon 359196392Ssimon sending = YES; 360196392Ssimon if (ruptible) 361196392Ssimon signal(SIGINT, onintr); 362196392Ssimon 363196392Ssimon if (isatty(fileno(stdin))) { 364196392Ssimon ptr = getpwuid(uid)->pw_name; 365196392Ssimon printf("Message %d:\nFrom %s %sSubject: ", 366196392Ssimon nextmsg, ptr, ctime(&t)); 367196392Ssimon fflush(stdout); 368196392Ssimon fgets(inbuf, sizeof inbuf, stdin); 369196392Ssimon putchar('\n'); 370196392Ssimon fflush(stdout); 371196392Ssimon fprintf(newmsg, "From %s %sSubject: %s\n", 372196392Ssimon ptr, ctime(&t), inbuf); 373196392Ssimon blankline = seensubj = YES; 374196392Ssimon } 375196392Ssimon else 376196392Ssimon blankline = seensubj = NO; 377196392Ssimon for (;;) { 378196392Ssimon fgets(inbuf, sizeof inbuf, stdin); 379196392Ssimon if (feof(stdin) || ferror(stdin)) 380196392Ssimon break; 381196392Ssimon blankline = (blankline || (inbuf[0] == '\n')); 382196392Ssimon seensubj = (seensubj || (!blankline && (strncmp(inbuf, "Subj", 4) == 0))); 383196392Ssimon fputs(inbuf, newmsg); 384196392Ssimon } 385196392Ssimon#ifdef OBJECT 386196392Ssimon if (!seensubj) { 387196392Ssimon printf("NOTICE: Messages should have a Subject field!\n"); 388196392Ssimon#ifdef REJECT 389161748Scperciva unlink(fname); 390161748Scperciva#endif 391161748Scperciva exit(1); 392161748Scperciva } 393161748Scperciva#endif 394161748Scperciva exit(ferror(stdin)); 395161748Scperciva } 396161748Scperciva if (clean) 397161748Scperciva exit(0); 398161748Scperciva 399161748Scperciva /* 400161748Scperciva * prepare to display messages 401161748Scperciva */ 402161748Scperciva totty = (isatty(fileno(stdout)) != 0); 403161748Scperciva use_pager = use_pager && totty; 404161748Scperciva 405161748Scperciva snprintf(fname, sizeof(fname), "%s/%s", getenv("HOME"), MSGSRC); 406161748Scperciva msgsrc = fopen(fname, "r"); 407161748Scperciva if (msgsrc) { 408161748Scperciva newrc = NO; 409161748Scperciva fscanf(msgsrc, "%d\n", &nextmsg); 410161748Scperciva fclose(msgsrc); 411161748Scperciva if (nextmsg > lastmsg+1) { 412161748Scperciva printf("Warning: bounds have been reset (%d, %d)\n", 413282870Sdelphij firstmsg, lastmsg); 414282870Sdelphij truncate(fname, (off_t)0); 415282870Sdelphij newrc = YES; 416282870Sdelphij } 417282870Sdelphij else if (!rcfirst) 418282870Sdelphij rcfirst = nextmsg - rcback; 419161748Scperciva } 420161748Scperciva else 421161748Scperciva newrc = YES; 422161748Scperciva msgsrc = fopen(fname, "r+"); 423161748Scperciva if (msgsrc == NULL) 424161748Scperciva msgsrc = fopen(fname, "w"); 425161748Scperciva if (msgsrc == NULL) 426161748Scperciva err(errno, "%s", fname); 427161748Scperciva if (rcfirst) { 428161748Scperciva if (rcfirst > lastmsg+1) { 429161748Scperciva printf("Warning: the last message is number %d.\n", 430161748Scperciva lastmsg); 431282870Sdelphij rcfirst = nextmsg; 432282870Sdelphij } 433282870Sdelphij if (rcfirst > firstmsg) 434282870Sdelphij firstmsg = rcfirst; /* don't set below first msg */ 435282870Sdelphij } 436282870Sdelphij if (newrc) { 437161748Scperciva nextmsg = firstmsg; 438161748Scperciva rewind(msgsrc); 439161748Scperciva fprintf(msgsrc, "%d\n", nextmsg); 440161748Scperciva fflush(msgsrc); 441161748Scperciva } 442161748Scperciva 443161748Scperciva#ifdef V7 444161748Scperciva if (totty) { 445161748Scperciva struct winsize win; 446161748Scperciva if (ioctl(fileno(stdout), TIOCGWINSZ, &win) != -1) 447161748Scperciva Lpp = win.ws_row; 448161748Scperciva if (Lpp <= 0) { 449161748Scperciva if (tgetent(inbuf, getenv("TERM")) <= 0 450161748Scperciva || (Lpp = tgetnum("li")) <= 0) { 451161748Scperciva Lpp = NLINES; 452161748Scperciva } 453161748Scperciva } 454161748Scperciva } 455173564Scperciva#endif 456173564Scperciva Lpp -= 6; /* for headers, etc. */ 457173564Scperciva 458173564Scperciva already = NO; 459161748Scperciva prevmsg = firstmsg; 460161748Scperciva printing = YES; 461161748Scperciva if (ruptible) 462161748Scperciva signal(SIGINT, onintr); 463161748Scperciva 464161748Scperciva /* 465161748Scperciva * Main program loop 466161748Scperciva */ 467161748Scperciva for (msg = firstmsg; msg <= lastmsg; msg++) { 468161748Scperciva 469161748Scperciva snprintf(fname, sizeof(fname), "%s/%d", _PATH_MSGS, msg); 470161748Scperciva newmsg = fopen(fname, "r"); 471161748Scperciva if (newmsg == NULL) 472161748Scperciva continue; 473161748Scperciva 474161748Scperciva gfrsub(newmsg); /* get From and Subject fields */ 475161748Scperciva if (locomode && !local) { 476161748Scperciva fclose(newmsg); 477181142Scperciva continue; 478161748Scperciva } 479161748Scperciva 480161748Scperciva if (qopt) { /* This has to be located here */ 481161748Scperciva printf("There are new messages.\n"); 482161748Scperciva exit(0); 483161748Scperciva } 484161748Scperciva 485161748Scperciva if (already && !hdrs) 486161748Scperciva putchar('\n'); 487161748Scperciva 488161748Scperciva /* 489161748Scperciva * Print header 490161748Scperciva */ 491161748Scperciva if (totty) 492161748Scperciva signal(SIGTSTP, onsusp); 493161748Scperciva (void) setjmp(tstpbuf); 494161748Scperciva already = YES; 495161748Scperciva nlines = 2; 496161748Scperciva if (seenfrom) { 497161748Scperciva printf("Message %d:\nFrom %s %s", msg, from, date); 498161748Scperciva nlines++; 499161748Scperciva } 500161748Scperciva if (seensubj) { 501161748Scperciva printf("Subject: %s", subj); 502161748Scperciva nlines++; 503161748Scperciva } 504161748Scperciva else { 505161748Scperciva if (seenfrom) { 506161748Scperciva putchar('\n'); 507161748Scperciva nlines++; 508161748Scperciva } 509161748Scperciva while (nlines < 6 510161748Scperciva && fgets(inbuf, sizeof inbuf, newmsg) 511161748Scperciva && inbuf[0] != '\n') { 512161748Scperciva fputs(inbuf, stdout); 513161748Scperciva nlines++; 514161748Scperciva } 515161748Scperciva } 516161748Scperciva 517161748Scperciva lct = linecnt(newmsg); 518161748Scperciva if (lct) 519161748Scperciva printf("(%d%slines) ", lct, seensubj? " " : " more "); 520161748Scperciva 521161748Scperciva if (hdrs) { 522161748Scperciva printf("\n-----\n"); 523161748Scperciva fclose(newmsg); 524161748Scperciva continue; 525161748Scperciva } 526161748Scperciva 527161748Scperciva /* 528161748Scperciva * Ask user for command 529161748Scperciva */ 530161748Scperciva if (totty) 531161748Scperciva ask(lct? MORE : (msg==lastmsg? NOMORE : NEXT)); 532161748Scperciva else 533161748Scperciva inbuf[0] = 'y'; 534161748Scperciva if (totty) 535161748Scperciva signal(SIGTSTP, SIG_DFL); 536161748Scpercivacmnd: 537161748Scperciva in = inbuf; 538161748Scperciva switch (*in) { 539161748Scperciva case 'x': 540161748Scperciva /* FALLTHROUGH */ 541161748Scperciva case 'X': 542161748Scperciva exit(0); 543161748Scperciva /* NOTREACHED */ 544161748Scperciva 545161748Scperciva case 'q': 546161748Scperciva /* FALLTHROUGH */ 547161748Scperciva case 'Q': 548161748Scperciva quitit = YES; 549161748Scperciva printf("--Postponed--\n"); 550161748Scperciva exit(0); 551161748Scperciva /* NOTREACHED */ 552161748Scperciva 553173564Scperciva case 'n': 554196392Ssimon /* FALLTHROUGH */ 555196392Ssimon case 'N': 556196392Ssimon if (msg >= nextmsg) sep = "Flushed"; 557161748Scperciva prevmsg = msg; 558161748Scperciva break; 559161748Scperciva 560161748Scperciva case 'p': 561161748Scperciva /* FALLTHROUGH */ 562161748Scperciva case 'P': 563161748Scperciva use_pager = (*in++ == 'p'); 564161748Scperciva /* FALLTHROUGH */ 565161748Scperciva case '\n': 566161748Scperciva /* FALLTHROUGH */ 567161748Scperciva case 'y': 568161748Scperciva default: 569161748Scperciva if (*in == '-') { 570161748Scperciva msg = prevmsg-1; 571161748Scperciva sep = "replay"; 572161748Scperciva break; 573161748Scperciva } 574161748Scperciva if (isdigit(*in)) { 575161748Scperciva msg = next(in); 576161748Scperciva sep = in; 577161748Scperciva break; 578161748Scperciva } 579161748Scperciva 580161748Scperciva prmesg(nlines + lct + (seensubj? 1 : 0)); 581161748Scperciva prevmsg = msg; 582161748Scperciva 583161748Scperciva } 584161748Scperciva 585161748Scperciva printf("--%s--\n", sep); 586161748Scperciva sep = "-"; 587161748Scperciva if (msg >= nextmsg) { 588161748Scperciva nextmsg = msg + 1; 589161748Scperciva rewind(msgsrc); 590161748Scperciva fprintf(msgsrc, "%d\n", nextmsg); 591161748Scperciva fflush(msgsrc); 592161748Scperciva } 593161748Scperciva if (newmsg) 594161748Scperciva fclose(newmsg); 595161748Scperciva if (quitit) 596161748Scperciva break; 597161748Scperciva } 598212434Scperciva 599161748Scperciva /* 600161748Scperciva * Make sure .rc file gets updated 601161748Scperciva */ 602161748Scperciva if (--msg >= nextmsg) { 603161748Scperciva nextmsg = msg + 1; 604161748Scperciva rewind(msgsrc); 605161748Scperciva fprintf(msgsrc, "%d\n", nextmsg); 606284938Sdelphij fflush(msgsrc); 607161748Scperciva } 608161748Scperciva if (already && !quitit && lastcmd && totty) { 609161748Scperciva /* 610161748Scperciva * save or reply to last message? 611161748Scperciva */ 612161748Scperciva msg = prevmsg; 613161748Scperciva ask(NOMORE); 614161748Scperciva if (inbuf[0] == '-' || isdigit(inbuf[0])) 615161748Scperciva goto cmnd; 616161748Scperciva } 617161748Scperciva if (!(already || hush || qopt)) 618161748Scperciva printf("No new messages.\n"); 619161748Scperciva exit(0); 620161748Scperciva /* NOTREACHED */ 621161748Scperciva} 622161748Scperciva 623161748Scpercivastatic void 624161748Scpercivausage(void) 625161748Scperciva{ 626161748Scperciva fprintf(stderr, "usage: msgs [fhlopq] [[-]number]\n"); 627161748Scperciva exit(1); 628161748Scperciva} 629161748Scperciva 630284938Sdelphijvoid 631284938Sdelphijprmesg(int length) 632284938Sdelphij{ 633284938Sdelphij FILE *outf; 634284938Sdelphij char *env_pager; 635284938Sdelphij 636284938Sdelphij if (use_pager && length > Lpp) { 637200054Scperciva signal(SIGPIPE, SIG_IGN); 638161748Scperciva signal(SIGQUIT, SIG_IGN); 639161748Scperciva if ((env_pager = getenv("PAGER")) == NULL) { 640161748Scperciva snprintf(cmdbuf, sizeof(cmdbuf), _PATH_PAGER, Lpp); 641161748Scperciva } else { 642161748Scperciva snprintf(cmdbuf, sizeof(cmdbuf), "%s", env_pager); 643161748Scperciva } 644161748Scperciva outf = popen(cmdbuf, "w"); 645161748Scperciva if (!outf) 646161748Scperciva outf = stdout; 647161748Scperciva else 648161748Scperciva setbuf(outf, (char *)NULL); 649173564Scperciva } 650161748Scperciva else 651161748Scperciva outf = stdout; 652161748Scperciva 653161748Scperciva if (seensubj) 654161748Scperciva putc('\n', outf); 655161748Scperciva 656161748Scperciva while (fgets(inbuf, sizeof inbuf, newmsg)) { 657161748Scperciva fputs(inbuf, outf); 658161748Scperciva if (ferror(outf)) { 659167189Scperciva clearerr(outf); 660167189Scperciva break; 661167189Scperciva } 662167189Scperciva } 663167189Scperciva 664167189Scperciva if (outf != stdout) { 665167189Scperciva pclose(outf); 666167189Scperciva signal(SIGPIPE, SIG_DFL); 667167189Scperciva signal(SIGQUIT, SIG_DFL); 668167189Scperciva } 669167189Scperciva else { 670167189Scperciva fflush(stdout); 671167189Scperciva } 672167189Scperciva 673167189Scperciva /* force wait on output */ 674167189Scperciva tcdrain(fileno(stdout)); 675167189Scperciva} 676167189Scperciva 677161748Scpercivavoid 678161748Scpercivaonintr(int unused __unused) 679161748Scperciva{ 680161748Scperciva signal(SIGINT, onintr); 681161748Scperciva if (mailing) 682161748Scperciva unlink(fname); 683161748Scperciva if (sending) { 684161748Scperciva unlink(fname); 685161748Scperciva puts("--Killed--"); 686161748Scperciva exit(1); 687161748Scperciva } 688161748Scperciva if (printing) { 689212434Scperciva putchar('\n'); 690212434Scperciva if (hdrs) 691212434Scperciva exit(0); 692212434Scperciva sep = "Interrupt"; 693212434Scperciva if (newmsg) 694212434Scperciva fseeko(newmsg, (off_t)0, SEEK_END); 695212434Scperciva intrpflg = YES; 696212434Scperciva } 697212434Scperciva} 698212434Scperciva 699282870Sdelphij/* 700282870Sdelphij * We have just gotten a susp. Suspend and prepare to resume. 701282870Sdelphij */ 702282870Sdelphijvoid 703282870Sdelphijonsusp(int unused __unused) 704282870Sdelphij{ 705282870Sdelphij signal(SIGTSTP, SIG_DFL); 706282870Sdelphij sigsetmask(0); 707212434Scperciva kill(0, SIGTSTP); 708212434Scperciva signal(SIGTSTP, onsusp); 709173564Scperciva if (!mailing) 710173564Scperciva longjmp(tstpbuf, 0); 711212434Scperciva} 712173564Scperciva 713173564Scpercivaint 714173564Scpercivalinecnt(FILE *f) 715173564Scperciva{ 716173564Scperciva off_t oldpos = ftello(f); 717173564Scperciva int l = 0; 718173564Scperciva char lbuf[BUFSIZ]; 719173564Scperciva 720173564Scperciva while (fgets(lbuf, sizeof lbuf, f)) 721173564Scperciva l++; 722173564Scperciva clearerr(f); 723173564Scperciva fseeko(f, oldpos, SEEK_SET); 724173564Scperciva return (l); 725173564Scperciva} 726173564Scperciva 727173564Scpercivaint 728173564Scpercivanext(char *buf) 729173564Scperciva{ 730173564Scperciva int i; 731173564Scperciva sscanf(buf, "%d", &i); 732173564Scperciva sprintf(buf, "Goto %d", i); 733173564Scperciva return(--i); 734173564Scperciva} 735173564Scperciva 736173564Scpercivavoid 737173564Scpercivaask(const char *prompt) 738173564Scperciva{ 739173564Scperciva char inch; 740173564Scperciva int n, cmsg, fd; 741173564Scperciva off_t oldpos; 742173564Scperciva FILE *cpfrom, *cpto; 743173564Scperciva 744173564Scperciva printf("%s ", prompt); 745173564Scperciva fflush(stdout); 746173564Scperciva intrpflg = NO; 747173564Scperciva (void) fgets(inbuf, sizeof inbuf, stdin); 748173564Scperciva if ((n = strlen(inbuf)) > 0 && inbuf[n - 1] == '\n') 749161748Scperciva inbuf[n - 1] = '\0'; 750161748Scperciva if (intrpflg) 751161748Scperciva inbuf[0] = 'x'; 752161748Scperciva 753161748Scperciva /* 754161748Scperciva * Handle 'mail' and 'save' here. 755161748Scperciva */ 756161748Scperciva if ((inch = inbuf[0]) == 's' || inch == 'm') { 757161748Scperciva if (inbuf[1] == '-') 758173441Scperciva cmsg = prevmsg; 759173441Scperciva else if (isdigit(inbuf[1])) 760173441Scperciva cmsg = atoi(&inbuf[1]); 761173441Scperciva else 762173441Scperciva cmsg = msg; 763173441Scperciva snprintf(fname, sizeof(fname), "%s/%d", _PATH_MSGS, cmsg); 764173441Scperciva 765161748Scperciva oldpos = ftello(newmsg); 766161748Scperciva 767161748Scperciva cpfrom = fopen(fname, "r"); 768161748Scperciva if (!cpfrom) { 769161748Scperciva printf("Message %d not found\n", cmsg); 770161748Scperciva ask (prompt); 771161748Scperciva return; 772161748Scperciva } 773161748Scperciva 774161748Scperciva if (inch == 's') { 775161748Scperciva in = nxtfld(inbuf); 776161748Scperciva if (*in) { 777161748Scperciva for (n=0; in[n] > ' '; n++) { /* sizeof fname? */ 778161748Scperciva fname[n] = in[n]; 779161748Scperciva } 780161748Scperciva fname[n] = NULL; 781161748Scperciva } 782161748Scperciva else 783161748Scperciva strcpy(fname, "Messages"); 784161748Scperciva fd = open(fname, O_RDWR|O_EXCL|O_CREAT|O_APPEND); 785161748Scperciva } 786161748Scperciva else { 787161748Scperciva strcpy(fname, _PATH_TMP); 788161748Scperciva fd = mkstemp(fname); 789161748Scperciva if (fd != -1) { 790196392Ssimon snprintf(cmdbuf, sizeof(cmdbuf), _PATH_MAIL, 791196392Ssimon fname); 792196392Ssimon mailing = YES; 793196392Ssimon } 794196392Ssimon } 795196392Ssimon if (fd == -1 || (cpto = fdopen(fd, "a")) == NULL) { 796196392Ssimon if (fd != -1) 797196392Ssimon close(fd); 798161748Scperciva warn("%s", fname); 799161748Scperciva mailing = NO; 800161748Scperciva fseeko(newmsg, oldpos, SEEK_SET); 801161748Scperciva ask(prompt); 802161748Scperciva return; 803161748Scperciva } 804161748Scperciva 805161748Scperciva while ((n = fread(inbuf, 1, sizeof inbuf, cpfrom))) 806161748Scperciva fwrite(inbuf, 1, n, cpto); 807161748Scperciva 808161748Scperciva fclose(cpfrom); 809161748Scperciva fclose(cpto); 810161748Scperciva fseeko(newmsg, oldpos, SEEK_SET);/* reposition current message */ 811161748Scperciva if (inch == 's') 812161748Scperciva printf("Message %d saved in \"%s\"\n", cmsg, fname); 813161748Scperciva else { 814161748Scperciva system(cmdbuf); 815161748Scperciva unlink(fname); 816161748Scperciva mailing = NO; 817161748Scperciva } 818161748Scperciva ask(prompt); 819161748Scperciva } 820161748Scperciva} 821161748Scperciva 822161748Scpercivavoid 823161748Scpercivagfrsub(FILE *infile) 824161748Scperciva{ 825161748Scperciva off_t frompos; 826161748Scperciva int count; 827161748Scperciva 828161748Scperciva seensubj = seenfrom = NO; 829161748Scperciva local = YES; 830161748Scperciva subj[0] = from[0] = date[0] = NULL; 831161748Scperciva 832161748Scperciva /* 833161748Scperciva * Is this a normal message? 834181142Scperciva */ 835181142Scperciva if (fgets(inbuf, sizeof inbuf, infile)) { 836181142Scperciva if (strncmp(inbuf, "From", 4)==0) { 837181142Scperciva /* 838181142Scperciva * expected form starts with From 839181142Scperciva */ 840181142Scperciva seenfrom = YES; 841181142Scperciva frompos = ftello(infile); 842181142Scperciva ptr = from; 843181142Scperciva in = nxtfld(inbuf); 844181142Scperciva if (*in) { 845181142Scperciva count = sizeof(from) - 1; 846181142Scperciva while (*in && *in > ' ' && count-- > 0) { 847181142Scperciva if (*in == ':' || *in == '@' || 848181142Scperciva *in == '!') 849181142Scperciva local = NO; 850181142Scperciva *ptr++ = *in++; 851181142Scperciva } 852181142Scperciva } 853181142Scperciva *ptr = NULL; 854181142Scperciva if (*(in = nxtfld(in))) 855181142Scperciva strncpy(date, in, sizeof date); 856181142Scperciva else { 857181142Scperciva date[0] = '\n'; 858181142Scperciva date[1] = NULL; 859181142Scperciva } 860181142Scperciva } 861181142Scperciva else { 862181142Scperciva /* 863181142Scperciva * not the expected form 864181142Scperciva */ 865181142Scperciva rewind(infile); 866181142Scperciva return; 867181142Scperciva } 868181142Scperciva } 869181142Scperciva else 870181142Scperciva /* 871181142Scperciva * empty file ? 872181142Scperciva */ 873181142Scperciva return; 874181142Scperciva 875181142Scperciva /* 876181142Scperciva * look for Subject line until EOF or a blank line 877181142Scperciva */ 878181142Scperciva while (fgets(inbuf, sizeof inbuf, infile) 879181142Scperciva && !(blankline = (inbuf[0] == '\n'))) { 880181142Scperciva /* 881181142Scperciva * extract Subject line 882181142Scperciva */ 883181142Scperciva if (!seensubj && strncmp(inbuf, "Subj", 4)==0) { 884181142Scperciva seensubj = YES; 885181142Scperciva frompos = ftello(infile); 886181142Scperciva strncpy(subj, nxtfld(inbuf), sizeof subj); 887181142Scperciva } 888181142Scperciva } 889181142Scperciva if (!blankline) 890181142Scperciva /* 891181142Scperciva * ran into EOF 892181142Scperciva */ 893181142Scperciva fseeko(infile, frompos, SEEK_SET); 894181142Scperciva 895181142Scperciva if (!seensubj) 896181142Scperciva /* 897181142Scperciva * for possible use with Mail 898181142Scperciva */ 899181142Scperciva strncpy(subj, "(No Subject)\n", sizeof subj); 900181142Scperciva} 901181142Scperciva 902181142Scpercivachar * 903181142Scpercivanxtfld(unsigned char *s) 904181142Scperciva{ 905181142Scperciva if (*s) while (*s && !isspace(*s)) s++; /* skip over this field */ 906181142Scperciva if (*s) while (*s && isspace(*s)) s++; /* find start of next field */ 907181142Scperciva return (s); 908181142Scperciva} 909181142Scperciva