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