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