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