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