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