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.22 (Berkeley) 04/01/91"; 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 FILE *obuf; 266 void brokpipe(); 267 268 obuf = stdout; 269 if (setjmp(pipestop)) 270 goto close_pipe; 271 if (value("interactive") != NOSTR && 272 (page || (cp = value("crt")) != NOSTR)) { 273 nlines = 0; 274 if (!page) { 275 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) 276 nlines += message[*ip - 1].m_lines; 277 } 278 if (page || nlines > (*cp ? atoi(cp) : realscreenheight)) { 279 cp = value("PAGER"); 280 if (cp == NULL || *cp == '\0') 281 cp = _PATH_MORE; 282 obuf = Popen(cp, "w"); 283 if (obuf == NULL) { 284 perror(cp); 285 obuf = stdout; 286 } else 287 signal(SIGPIPE, brokpipe); 288 } 289 } 290 for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) { 291 mp = &message[*ip - 1]; 292 touch(mp); 293 dot = mp; 294 if (value("quiet") == NOSTR) 295 fprintf(obuf, "Message %d:\n", *ip); 296 (void) send(mp, obuf, doign ? ignore : 0, NOSTR); 297 } 298 close_pipe: 299 if (obuf != stdout) { 300 /* 301 * Ignore SIGPIPE so it can't cause a duplicate close. 302 */ 303 signal(SIGPIPE, SIG_IGN); 304 Pclose(obuf); 305 signal(SIGPIPE, SIG_DFL); 306 } 307 return(0); 308 } 309 310 /* 311 * Respond to a broken pipe signal -- 312 * probably caused by quitting more. 313 */ 314 315 void 316 brokpipe() 317 { 318 longjmp(pipestop, 1); 319 } 320 321 /* 322 * Print the top so many lines of each desired message. 323 * The number of lines is taken from the variable "toplines" 324 * and defaults to 5. 325 */ 326 327 top(msgvec) 328 int *msgvec; 329 { 330 register int *ip; 331 register struct message *mp; 332 int c, topl, lines, lineb; 333 char *valtop, linebuf[LINESIZE]; 334 FILE *ibuf; 335 336 topl = 5; 337 valtop = value("toplines"); 338 if (valtop != NOSTR) { 339 topl = atoi(valtop); 340 if (topl < 0 || topl > 10000) 341 topl = 5; 342 } 343 lineb = 1; 344 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 345 mp = &message[*ip - 1]; 346 touch(mp); 347 dot = mp; 348 if (value("quiet") == NOSTR) 349 printf("Message %d:\n", *ip); 350 ibuf = setinput(mp); 351 c = mp->m_lines; 352 if (!lineb) 353 printf("\n"); 354 for (lines = 0; lines < c && lines <= topl; lines++) { 355 if (readline(ibuf, linebuf, LINESIZE) < 0) 356 break; 357 puts(linebuf); 358 lineb = blankline(linebuf); 359 } 360 } 361 return(0); 362 } 363 364 /* 365 * Touch all the given messages so that they will 366 * get mboxed. 367 */ 368 stouch(msgvec) 369 int msgvec[]; 370 { 371 register int *ip; 372 373 for (ip = msgvec; *ip != 0; ip++) { 374 dot = &message[*ip-1]; 375 dot->m_flag |= MTOUCH; 376 dot->m_flag &= ~MPRESERVE; 377 } 378 return(0); 379 } 380 381 /* 382 * Make sure all passed messages get mboxed. 383 */ 384 385 mboxit(msgvec) 386 int msgvec[]; 387 { 388 register int *ip; 389 390 for (ip = msgvec; *ip != 0; ip++) { 391 dot = &message[*ip-1]; 392 dot->m_flag |= MTOUCH|MBOX; 393 dot->m_flag &= ~MPRESERVE; 394 } 395 return(0); 396 } 397 398 /* 399 * List the folders the user currently has. 400 */ 401 folders() 402 { 403 char dirname[BUFSIZ]; 404 char *cmd; 405 406 if (getfold(dirname) < 0) { 407 printf("No value set for \"folder\"\n"); 408 return 1; 409 } 410 if ((cmd = value("LISTER")) == NOSTR) 411 cmd = "ls"; 412 (void) run_command(cmd, 0, -1, -1, dirname, NOSTR); 413 return 0; 414 } 415