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 32 static char sccsid[] = "@(#)cmd1.c 8.2 (Berkeley) 4/20/95"; 33 #endif 34 #endif /* not lint */ 35 #include <sys/cdefs.h> 36 __FBSDID("$FreeBSD$"); 37 38 #include "rcv.h" 39 #include "extern.h" 40 41 /* 42 * Mail -- a mail program 43 * 44 * User commands. 45 */ 46 47 extern 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 54 static int screen; 55 56 int 57 headers(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 */ 96 int 97 scroll(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 */ 135 int 136 screensize() 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 */ 150 int 151 from(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 */ 167 void 168 printhead(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 */ 214 int 215 pdot() 216 { 217 printf("%d\n", dot - &message[0] + 1); 218 return (0); 219 } 220 221 /* 222 * Print out all the possible commands. 223 */ 224 int 225 pcmdlist() 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 */ 248 int 249 more(msgvec) 250 int *msgvec; 251 { 252 253 return (type1(msgvec, 1, 1)); 254 } 255 256 /* 257 * Paginate messages, even printing ignored fields. 258 */ 259 int 260 More(msgvec) 261 int *msgvec; 262 { 263 264 return (type1(msgvec, 0, 1)); 265 } 266 267 /* 268 * Type out messages, honor ignored fields. 269 */ 270 int 271 type(msgvec) 272 int *msgvec; 273 { 274 275 return (type1(msgvec, 1, 0)); 276 } 277 278 /* 279 * Type out messages, even printing ignored fields. 280 */ 281 int 282 Type(msgvec) 283 int *msgvec; 284 { 285 286 return (type1(msgvec, 0, 0)); 287 } 288 289 /* 290 * Type out the messages requested. 291 */ 292 static jmp_buf pipestop; 293 int 294 type1(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 339 close_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*/ 356 void 357 brokpipe(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 */ 368 int 369 top(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 */ 410 int 411 stouch(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 */ 427 int 428 mboxit(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 */ 444 int 445 folders() 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 */ 464 int 465 inc(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