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