cmd1.c revision 336953
11539Srgrimes/*- 21539Srgrimes * Copyright (c) 1980, 1993 31539Srgrimes * The Regents of the University of California. All rights reserved. 41539Srgrimes * 51539Srgrimes * Redistribution and use in source and binary forms, with or without 61539Srgrimes * modification, are permitted provided that the following conditions 71539Srgrimes * are met: 81539Srgrimes * 1. Redistributions of source code must retain the above copyright 91539Srgrimes * notice, this list of conditions and the following disclaimer. 101539Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111539Srgrimes * notice, this list of conditions and the following disclaimer in the 121539Srgrimes * documentation and/or other materials provided with the distribution. 131539Srgrimes * 4. Neither the name of the University nor the names of its contributors 141539Srgrimes * may be used to endorse or promote products derived from this software 151539Srgrimes * without specific prior written permission. 161539Srgrimes * 171539Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181539Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191539Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201539Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211539Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221539Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231539Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241539Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251539Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261539Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271539Srgrimes * SUCH DAMAGE. 281539Srgrimes */ 291539Srgrimes 301539Srgrimes#ifndef lint 311539Srgrimes#if 0 321539Srgrimesstatic char sccsid[] = "@(#)cmd1.c 8.2 (Berkeley) 4/20/95"; 3341284Sbde#endif 3450473Speter#endif /* not lint */ 351539Srgrimes#include <sys/cdefs.h> 361539Srgrimes__FBSDID("$FreeBSD: stable/10/usr.bin/mail/cmd1.c 336953 2018-07-31 00:37:25Z markj $"); 371539Srgrimes 381539Srgrimes#include "rcv.h" 391539Srgrimes#include "extern.h" 401539Srgrimes 411539Srgrimes/* 421539Srgrimes * Mail -- a mail program 431539Srgrimes * 441539Srgrimes * User commands. 451539Srgrimes */ 461539Srgrimes 471539Srgrimesextern const struct cmd cmdtab[]; 481539Srgrimes 491539Srgrimes/* 501539Srgrimes * Print the current active headings. 5193032Simp * Don't change dot if invoker didn't give an argument. 5293032Simp */ 5341284Sbde 5493032Simpstatic int screen; 5593032Simp 5641284Sbdeint 5793032Simpheaders(int *msgvec) 5893032Simp{ 5941284Sbde int n, mesg, flag, size; 6093032Simp struct message *mp; 6193032Simp 6293032Simp size = screensize(); 6393032Simp n = msgvec[0]; 6493032Simp if (n != 0) 6593032Simp screen = (n-1)/size; 6693032Simp if (screen < 0) 6793032Simp screen = 0; 681539Srgrimes mp = &message[screen * size]; 691539Srgrimes if (mp >= &message[msgCount]) 701539Srgrimes mp = &message[msgCount - size]; 71 if (mp < &message[0]) 72 mp = &message[0]; 73 flag = 0; 74 mesg = mp - &message[0]; 75 if (dot != &message[n-1]) 76 dot = mp; 77 for (; mp < &message[msgCount]; mp++) { 78 mesg++; 79 if (mp->m_flag & MDELETED) 80 continue; 81 if (flag++ >= size) 82 break; 83 printhead(mesg); 84 } 85 if (flag == 0) { 86 printf("No more mail.\n"); 87 return (1); 88 } 89 return (0); 90} 91 92/* 93 * Scroll to the next/previous screen 94 */ 95int 96scroll(char arg[]) 97{ 98 int s, size; 99 int cur[1]; 100 101 cur[0] = 0; 102 size = screensize(); 103 s = screen; 104 switch (*arg) { 105 case 0: 106 case '+': 107 s++; 108 if (s * size >= msgCount) { 109 printf("On last screenful of messages\n"); 110 return (0); 111 } 112 screen = s; 113 break; 114 115 case '-': 116 if (--s < 0) { 117 printf("On first screenful of messages\n"); 118 return (0); 119 } 120 screen = s; 121 break; 122 123 default: 124 printf("Unrecognized scrolling command \"%s\"\n", arg); 125 return (1); 126 } 127 return (headers(cur)); 128} 129 130/* 131 * Compute screen size. 132 */ 133int 134screensize(void) 135{ 136 int s; 137 char *cp; 138 139 if ((cp = value("screen")) != NULL && (s = atoi(cp)) > 0) 140 return (s); 141 return (screenheight - 4); 142} 143 144/* 145 * Print out the headlines for each message 146 * in the passed message list. 147 */ 148int 149from(int *msgvec) 150{ 151 int *ip; 152 153 for (ip = msgvec; *ip != 0; ip++) 154 printhead(*ip); 155 if (--ip >= msgvec) 156 dot = &message[*ip - 1]; 157 return (0); 158} 159 160/* 161 * Print out the header of a specific message. 162 * This is a slight improvement to the standard one. 163 */ 164void 165printhead(int mesg) 166{ 167 struct message *mp; 168 char headline[LINESIZE], wcount[LINESIZE], *subjline, dispc, curind; 169 char pbuf[BUFSIZ]; 170 struct headline hl; 171 int subjlen; 172 char *name; 173 174 mp = &message[mesg-1]; 175 (void)readline(setinput(mp), headline, LINESIZE); 176 if ((subjline = hfield("subject", mp)) == NULL) 177 subjline = hfield("subj", mp); 178 /* 179 * Bletch! 180 */ 181 curind = dot == mp ? '>' : ' '; 182 dispc = ' '; 183 if (mp->m_flag & MSAVED) 184 dispc = '*'; 185 if (mp->m_flag & MPRESERVE) 186 dispc = 'P'; 187 if ((mp->m_flag & (MREAD|MNEW)) == MNEW) 188 dispc = 'N'; 189 if ((mp->m_flag & (MREAD|MNEW)) == 0) 190 dispc = 'U'; 191 if (mp->m_flag & MBOX) 192 dispc = 'M'; 193 parse(headline, &hl, pbuf); 194 sprintf(wcount, "%3ld/%-5ld", mp->m_lines, mp->m_size); 195 subjlen = screenwidth - 50 - strlen(wcount); 196 name = value("show-rcpt") != NULL ? 197 skin(hfield("to", mp)) : nameof(mp, 0); 198 if (subjline == NULL || subjlen < 0) /* pretty pathetic */ 199 printf("%c%c%3d %-20.20s %16.16s %s\n", 200 curind, dispc, mesg, name, hl.l_date, wcount); 201 else 202 printf("%c%c%3d %-20.20s %16.16s %s \"%.*s\"\n", 203 curind, dispc, mesg, name, hl.l_date, wcount, 204 subjlen, subjline); 205} 206 207/* 208 * Print out the value of dot. 209 */ 210int 211pdot(void) 212{ 213 printf("%td\n", dot - &message[0] + 1); 214 return (0); 215} 216 217/* 218 * Print out all the possible commands. 219 */ 220int 221pcmdlist(void) 222{ 223 const struct cmd *cp; 224 int cc; 225 226 printf("Commands are:\n"); 227 for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) { 228 cc += strlen(cp->c_name) + 2; 229 if (cc > 72) { 230 printf("\n"); 231 cc = strlen(cp->c_name) + 2; 232 } 233 if ((cp+1)->c_name != NULL) 234 printf("%s, ", cp->c_name); 235 else 236 printf("%s\n", cp->c_name); 237 } 238 return (0); 239} 240 241/* 242 * Paginate messages, honor ignored fields. 243 */ 244int 245more(int *msgvec) 246{ 247 248 return (type1(msgvec, 1, 1)); 249} 250 251/* 252 * Paginate messages, even printing ignored fields. 253 */ 254int 255More(int *msgvec) 256{ 257 258 return (type1(msgvec, 0, 1)); 259} 260 261/* 262 * Type out messages, honor ignored fields. 263 */ 264int 265type(int *msgvec) 266{ 267 268 return (type1(msgvec, 1, 0)); 269} 270 271/* 272 * Type out messages, even printing ignored fields. 273 */ 274int 275Type(int *msgvec) 276{ 277 278 return (type1(msgvec, 0, 0)); 279} 280 281/* 282 * Type out the messages requested. 283 */ 284static jmp_buf pipestop; 285int 286type1(int *msgvec, int doign, int page) 287{ 288 int nlines, *ip; 289 struct message *mp; 290 char *cp; 291 FILE *obuf; 292 293 obuf = stdout; 294 if (setjmp(pipestop)) 295 goto close_pipe; 296 if (value("interactive") != NULL && 297 (page || (cp = value("crt")) != NULL)) { 298 nlines = 0; 299 if (!page) { 300 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) 301 nlines += message[*ip - 1].m_lines; 302 } 303 if (page || nlines > (*cp ? atoi(cp) : realscreenheight)) { 304 cp = value("PAGER"); 305 if (cp == NULL || *cp == '\0') 306 cp = _PATH_MORE; 307 obuf = Popen(cp, "w"); 308 if (obuf == NULL) { 309 warnx("%s", cp); 310 obuf = stdout; 311 } else 312 (void)signal(SIGPIPE, brokpipe); 313 } 314 } 315 316 /* 317 * Send messages to the output. 318 * 319 */ 320 for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) { 321 mp = &message[*ip - 1]; 322 touch(mp); 323 dot = mp; 324 if (value("quiet") == NULL) 325 fprintf(obuf, "Message %d:\n", *ip); 326 (void)sendmessage(mp, obuf, doign ? ignore : 0, NULL); 327 } 328 329close_pipe: 330 if (obuf != stdout) { 331 /* 332 * Ignore SIGPIPE so it can't cause a duplicate close. 333 */ 334 (void)signal(SIGPIPE, SIG_IGN); 335 (void)Pclose(obuf); 336 (void)signal(SIGPIPE, SIG_DFL); 337 } 338 return (0); 339} 340 341/* 342 * Respond to a broken pipe signal -- 343 * probably caused by quitting more. 344 */ 345/*ARGSUSED*/ 346void 347brokpipe(int signo __unused) 348{ 349 longjmp(pipestop, 1); 350} 351 352/* 353 * Print the top so many lines of each desired message. 354 * The number of lines is taken from the variable "toplines" 355 * and defaults to 5. 356 */ 357int 358top(int *msgvec) 359{ 360 int *ip; 361 struct message *mp; 362 int c, topl, lines, lineb; 363 char *valtop, linebuf[LINESIZE]; 364 FILE *ibuf; 365 366 topl = 5; 367 valtop = value("toplines"); 368 if (valtop != NULL) { 369 topl = atoi(valtop); 370 if (topl < 0 || topl > 10000) 371 topl = 5; 372 } 373 lineb = 1; 374 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 375 mp = &message[*ip - 1]; 376 touch(mp); 377 dot = mp; 378 if (value("quiet") == NULL) 379 printf("Message %d:\n", *ip); 380 ibuf = setinput(mp); 381 c = mp->m_lines; 382 if (!lineb) 383 printf("\n"); 384 for (lines = 0; lines < c && lines <= topl; lines++) { 385 if (readline(ibuf, linebuf, sizeof(linebuf)) < 0) 386 break; 387 puts(linebuf); 388 lineb = strspn(linebuf, " \t") == strlen(linebuf); 389 } 390 } 391 return (0); 392} 393 394/* 395 * Touch all the given messages so that they will 396 * get mboxed. 397 */ 398int 399stouch(int msgvec[]) 400{ 401 int *ip; 402 403 for (ip = msgvec; *ip != 0; ip++) { 404 dot = &message[*ip-1]; 405 dot->m_flag |= MTOUCH; 406 dot->m_flag &= ~MPRESERVE; 407 } 408 return (0); 409} 410 411/* 412 * Make sure all passed messages get mboxed. 413 */ 414int 415mboxit(int msgvec[]) 416{ 417 int *ip; 418 419 for (ip = msgvec; *ip != 0; ip++) { 420 dot = &message[*ip-1]; 421 dot->m_flag |= MTOUCH|MBOX; 422 dot->m_flag &= ~MPRESERVE; 423 } 424 return (0); 425} 426 427/* 428 * List the folders the user currently has. 429 */ 430int 431folders(void) 432{ 433 char dirname[PATHSIZE]; 434 char *cmd; 435 436 if (getfold(dirname, sizeof(dirname)) < 0) { 437 printf("No value set for \"folder\"\n"); 438 return (1); 439 } 440 if ((cmd = value("LISTER")) == NULL) 441 cmd = "ls"; 442 (void)run_command(cmd, 0, -1, -1, dirname, NULL, NULL); 443 return (0); 444} 445 446/* 447 * Update the mail file with any new messages that have 448 * come in since we started reading mail. 449 */ 450int 451inc(void *v __unused) 452{ 453 int nmsg, mdot; 454 455 nmsg = incfile(); 456 457 if (nmsg == 0) 458 printf("No new mail.\n"); 459 else if (nmsg > 0) { 460 mdot = newfileinfo(msgCount - nmsg); 461 dot = &message[mdot - 1]; 462 } else 463 printf("\"inc\" command failed...\n"); 464 465 return (0); 466} 467