1 /* $NetBSD: cmd1.c,v 1.19 2002/03/29 15:07:52 ross 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 #include <sys/cdefs.h> 37 #ifndef lint 38 #if 0 39 static char sccsid[] = "@(#)cmd1.c 8.2 (Berkeley) 4/20/95"; 40 #else 41 __RCSID("$NetBSD: cmd1.c,v 1.19 2002/03/29 15:07:52 ross 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 extern const struct cmd cmdtab[]; 54 55 /* 56 * Print the current active headings. 57 * Don't change dot if invoker didn't give an argument. 58 */ 59 60 static int screen; 61 62 int 63 headers(void *v) 64 { 65 int *msgvec = v; 66 int n, mesg, flag; 67 struct message *mp; 68 int size; 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 */ 103 int 104 scroll(void *v) 105 { 106 char *arg = v; 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 */ 142 int 143 screensize(void) 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 */ 157 int 158 from(void *v) 159 { 160 int *msgvec = v; 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 */ 174 void 175 printhead(int mesg) 176 { 177 struct message *mp; 178 char headline[LINESIZE], wcount[LINESIZE], *subjline, dispc, curind; 179 char pbuf[BUFSIZ]; 180 struct headline hl; 181 int subjlen; 182 char *name; 183 184 mp = &message[mesg-1]; 185 (void)readline(setinput(mp), headline, LINESIZE); 186 if ((subjline = hfield("subject", mp)) == NULL) 187 subjline = hfield("subj", mp); 188 /* 189 * Bletch! 190 */ 191 curind = dot == mp ? '>' : ' '; 192 dispc = ' '; 193 if (mp->m_flag & MSAVED) 194 dispc = '*'; 195 if (mp->m_flag & MPRESERVE) 196 dispc = 'P'; 197 if ((mp->m_flag & (MREAD|MNEW)) == MNEW) 198 dispc = 'N'; 199 if ((mp->m_flag & (MREAD|MNEW)) == 0) 200 dispc = 'U'; 201 if (mp->m_flag & MBOX) 202 dispc = 'M'; 203 parse(headline, &hl, pbuf); 204 snprintf(wcount, LINESIZE, "%3ld/%-5ld", mp->m_blines, mp->m_size); 205 subjlen = screenwidth - 50 - strlen(wcount); 206 name = value("show-rcpt") != NULL ? 207 skin(hfield("to", mp)) : nameof(mp, 0); 208 if (subjline == NULL || subjlen < 0) /* pretty pathetic */ 209 printf("%c%c%3d %-20.20s %16.16s %s\n", 210 curind, dispc, mesg, name, hl.l_date, wcount); 211 else 212 printf("%c%c%3d %-20.20s %16.16s %s \"%.*s\"\n", 213 curind, dispc, mesg, name, hl.l_date, wcount, 214 subjlen, subjline); 215 } 216 217 /* 218 * Print out the value of dot. 219 */ 220 int 221 pdot(void *v) 222 { 223 printf("%d\n", (int)(dot - &message[0] + 1)); 224 return(0); 225 } 226 227 /* 228 * Print out all the possible commands. 229 */ 230 int 231 pcmdlist(void *v) 232 { 233 const struct cmd *cp; 234 int cc; 235 236 printf("Commands are:\n"); 237 for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) { 238 cc += strlen(cp->c_name) + 2; 239 if (cc > 72) { 240 printf("\n"); 241 cc = strlen(cp->c_name) + 2; 242 } 243 if ((cp+1)->c_name != NULL) 244 printf("%s, ", cp->c_name); 245 else 246 printf("%s\n", cp->c_name); 247 } 248 return(0); 249 } 250 251 /* 252 * Paginate messages, honor ignored fields. 253 */ 254 int 255 more(void *v) 256 { 257 int *msgvec = v; 258 return (type1(msgvec, 1, 1)); 259 } 260 261 /* 262 * Paginate messages, even printing ignored fields. 263 */ 264 int 265 More(void *v) 266 { 267 int *msgvec = v; 268 269 return (type1(msgvec, 0, 1)); 270 } 271 272 /* 273 * Type out messages, honor ignored fields. 274 */ 275 int 276 type(void *v) 277 { 278 int *msgvec = v; 279 280 return(type1(msgvec, 1, 0)); 281 } 282 283 /* 284 * Type out messages, even printing ignored fields. 285 */ 286 int 287 Type(void *v) 288 { 289 int *msgvec = v; 290 291 return(type1(msgvec, 0, 0)); 292 } 293 294 /* 295 * Type out the messages requested. 296 */ 297 jmp_buf pipestop; 298 int 299 type1(int *msgvec, int doign, int page) 300 { 301 int *ip; 302 struct message *mp; 303 char *cp; 304 int nlines; 305 FILE *obuf; 306 #if __GNUC__ 307 /* Avoid longjmp clobbering */ 308 (void)&cp; 309 (void)&obuf; 310 #endif 311 312 obuf = stdout; 313 if (setjmp(pipestop)) 314 goto close_pipe; 315 if (value("interactive") != NULL && 316 (page || (cp = value("crt")) != NULL)) { 317 nlines = 0; 318 if (!page) { 319 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) 320 nlines += message[*ip - 1].m_blines; 321 } 322 if (page || nlines > (*cp ? atoi(cp) : realscreenheight)) { 323 cp = value("PAGER"); 324 if (cp == NULL || *cp == '\0') 325 cp = _PATH_MORE; 326 obuf = Popen(cp, "w"); 327 if (obuf == NULL) { 328 warn("%s", cp); 329 obuf = stdout; 330 } else 331 signal(SIGPIPE, brokpipe); 332 } 333 } 334 for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) { 335 mp = &message[*ip - 1]; 336 touch(mp); 337 dot = mp; 338 if (value("quiet") == NULL) 339 fprintf(obuf, "Message %d:\n", *ip); 340 (void)sendmessage(mp, obuf, doign ? ignore : 0, NULL); 341 } 342 close_pipe: 343 if (obuf != stdout) { 344 /* 345 * Ignore SIGPIPE so it can't cause a duplicate close. 346 */ 347 signal(SIGPIPE, SIG_IGN); 348 Pclose(obuf); 349 signal(SIGPIPE, SIG_DFL); 350 } 351 return(0); 352 } 353 354 /* 355 * Respond to a broken pipe signal -- 356 * probably caused by quitting more. 357 */ 358 void 359 brokpipe(int signo) 360 { 361 longjmp(pipestop, 1); 362 } 363 364 /* 365 * Print the top so many lines of each desired message. 366 * The number of lines is taken from the variable "toplines" 367 * and defaults to 5. 368 */ 369 int 370 top(void *v) 371 { 372 int *msgvec = v; 373 int *ip; 374 struct message *mp; 375 int c, topl, lines, lineb; 376 char *valtop, linebuf[LINESIZE]; 377 FILE *ibuf; 378 379 topl = 5; 380 valtop = value("toplines"); 381 if (valtop != NULL) { 382 topl = atoi(valtop); 383 if (topl < 0 || topl > 10000) 384 topl = 5; 385 } 386 lineb = 1; 387 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 388 mp = &message[*ip - 1]; 389 touch(mp); 390 dot = mp; 391 if (value("quiet") == NULL) 392 printf("Message %d:\n", *ip); 393 ibuf = setinput(mp); 394 c = mp->m_lines; 395 if (!lineb) 396 printf("\n"); 397 for (lines = 0; lines < c && lines <= topl; lines++) { 398 if (readline(ibuf, linebuf, LINESIZE) < 0) 399 break; 400 puts(linebuf); 401 lineb = blankline(linebuf); 402 } 403 } 404 return(0); 405 } 406 407 /* 408 * Touch all the given messages so that they will 409 * get mboxed. 410 */ 411 int 412 stouch(void *v) 413 { 414 int *msgvec = v; 415 int *ip; 416 417 for (ip = msgvec; *ip != 0; ip++) { 418 dot = &message[*ip-1]; 419 dot->m_flag |= MTOUCH; 420 dot->m_flag &= ~MPRESERVE; 421 } 422 return(0); 423 } 424 425 /* 426 * Make sure all passed messages get mboxed. 427 */ 428 int 429 mboxit(void *v) 430 { 431 int *msgvec = v; 432 int *ip; 433 434 for (ip = msgvec; *ip != 0; ip++) { 435 dot = &message[*ip-1]; 436 dot->m_flag |= MTOUCH|MBOX; 437 dot->m_flag &= ~MPRESERVE; 438 } 439 return(0); 440 } 441 442 /* 443 * List the folders the user currently has. 444 */ 445 int 446 folders(void *v) 447 { 448 char dirname[PATHSIZE]; 449 char *cmd; 450 451 if (getfold(dirname) < 0) { 452 printf("No value set for \"folder\"\n"); 453 return 1; 454 } 455 if ((cmd = value("LISTER")) == NULL) 456 cmd = "ls"; 457 (void)run_command(cmd, 0, -1, -1, dirname, NULL, NULL); 458 return 0; 459 } 460 461 /* 462 * Update the mail file with any new messages that have 463 * come in since we started reading mail. 464 */ 465 int 466 inc(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 481 return 0; 482 } 483