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