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