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