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