/* Copyright (c) 1979 Regents of the University of California */ # #include "rcv.h" /* * Mail -- a mail program * * Message list handling. */ /* * Convert the user string of message numbers and * store the numbers into vector. * * Returns the count of messages picked up or -1 on error. */ getmsglist(buf, vector, flags) char *buf; int *vector; { register int *ip; register struct message *mp; if (markall(buf, flags) < 0) return(-1); ip = vector; for (mp = &message[0]; mp < &message[msgCount]; mp++) if (mp->m_flag & MMARK) *ip++ = mp - &message[0] + 1; *ip = NULL; return(ip - vector); } /* * Mark all messages that the user wanted from the command * line in the message structure. Return 0 on success, -1 * on error. */ markall(buf, f) char buf[]; { register char **np; register int i; char *namelist[NMLSIZE], *bufp; int tok, beg, mc, star, other; for (i = 1; i <= msgCount; i++) unmark(i); bufp = buf; mc = 0; np = &namelist[0]; scaninit(); tok = scan(&bufp); star = 0; other = 0; beg = 0; while (tok != TEOL) { switch (tok) { case TNUMBER: number: if (star) { printf("No numbers mixed with *\n"); return(-1); } mc++; other++; if (beg != 0) { if (check(lexnumber, f)) return(-1); for (i = beg; i <= lexnumber; i++) mark(i); beg = 0; break; } beg = lexnumber; if (check(beg, f)) return(-1); tok = scan(&bufp); regret(tok); if (tok != TDASH) { mark(beg); beg = 0; } break; case TDASH: if (beg == 0) { printf("Unexpected leading dash\n"); return(-1); } break; case TSTRING: if (beg != 0) { printf("Non-numeric second argument\n"); return(-1); } other++; *np++ = savestr(lexstring); break; case TDOLLAR: case TUP: case TDOT: lexnumber = metamess(lexstring[0], f); if (lexnumber == -1) return(-1); goto number; case TSTAR: if (other) { printf("Can't mix \"*\" with anything\n"); return(-1); } star++; break; } tok = scan(&bufp); } *np = NOSTR; mc = 0; if (star) { for (i = 0; i < msgCount; i++) if ((message[i].m_flag & MDELETED) == f) { mark(i+1); mc++; } if (mc == 0) { printf("No applicable messages.\n"); return(-1); } return(0); } /* * If no numbers were given, mark all of the messages, * so that we can unmark any whose sender was not selected * if any user names were given. */ if (np > namelist && mc == 0) for (i = 1; i <= msgCount; i++) if ((message[i-1].m_flag & (MSAVED|MDELETED)) == f) mark(i); /* * If any names were given, go through and eliminate any * messages whose senders were not requested. */ if (np > namelist) { for (i = 1; i <= msgCount; i++) { for (mc = 0, np = &namelist[0]; *np != NOSTR; np++) if (sender(*np, i)) { mc++; break; } if (mc == 0) unmark(i); } /* * Make sure we got some decent messages. */ mc = 0; for (i = 1; i <= msgCount; i++) if (message[i-1].m_flag & MMARK) { mc++; break; } if (mc == 0) { printf("No applicable messages from {%s", namelist[0]); for (np = &namelist[1]; *np != NOSTR; np++) printf(", %s", *np); printf("}\n"); return(-1); } } return(0); } /* * Check the passed message number for legality and proper flags. */ check(mesg, f) { register struct message *mp; if (mesg < 1 || mesg > msgCount) { printf("%d: Invalid message number\n", mesg); return(-1); } mp = &message[mesg-1]; if ((mp->m_flag & MDELETED) != f) { printf("%d: Inappropriate message\n", mesg); return(-1); } return(0); } /* * Scan out the list of string arguments, shell style * for a RAWLIST. */ getrawlist(line, argv) char line[]; char **argv; { register char **ap, *cp, *cp2; char linebuf[BUFSIZ], quotec; ap = argv; cp = line; while (*cp != '\0') { while (any(*cp, " \t")) cp++; cp2 = linebuf; quotec = 0; if (any(*cp, "'\"")) quotec = *cp++; if (quotec == 0) while (*cp != '\0' && !any(*cp, " \t")) *cp2++ = *cp++; else { while (*cp != '\0' && *cp != quotec) *cp2++ = *cp++; if (*cp != '\0') cp++; } *cp2 = '\0'; if (cp2 == linebuf) break; *ap++ = savestr(linebuf); } *ap = NOSTR; return(ap-argv); } /* * scan out a single lexical item and return its token number, * updating the string pointer passed **p. Also, store the value * of the number or string scanned in lexnumber or lexstring as * appropriate. In any event, store the scanned `thing' in lexstring. */ struct lex { char l_char; char l_token; } singles[] = { '$', TDOLLAR, '.', TDOT, '^', TUP, '*', TSTAR, '-', TDASH, '(', TOPEN, ')', TCLOSE, 0, 0 }; scan(sp) char **sp; { register char *cp, *cp2; register int c; register struct lex *lp; int quotec; if (regretp >= 0) { copy(stringstack[regretp], lexstring); lexnumber = numberstack[regretp]; return(regretstack[regretp--]); } cp = *sp; cp2 = lexstring; c = *cp++; /* * strip away leading white space. */ while (any(c, " \t")) c = *cp++; /* * If no characters remain, we are at end of line, * so report that. */ if (c == '\0') { *sp = --cp; return(TEOL); } /* * If the leading character is a digit, scan * the number and convert it on the fly. * Return TNUMBER when done. */ if (isdigit(c)) { lexnumber = 0; while (isdigit(c)) { lexnumber = lexnumber*10 + c - '0'; *cp2++ = c; c = *cp++; } *cp2 = '\0'; *sp = --cp; return(TNUMBER); } /* * Check for single character tokens; return such * if found. */ for (lp = &singles[0]; lp->l_char != 0; lp++) if (c == lp->l_char) { lexstring[0] = c; lexstring[1] = '\0'; *sp = cp; return(lp->l_token); } /* * We've got a string! Copy all the characters * of the string into lexstring, until we see * a null, space, or tab. * If the lead character is a " or ', save it * and scan until you get another. */ quotec = 0; if (any(c, "'\"")) { quotec = c; c = *cp++; } while (c != '\0') { if (c == quotec) break; if (quotec == 0 && any(c, " \t")) break; if (cp2 - lexstring < STRINGLEN-1) *cp2++ = c; c = *cp++; } if (quotec && c == 0) fprintf(stderr, "Missing %c\n", quotec); *sp = --cp; *cp2 = '\0'; return(TSTRING); } /* * Unscan the named token by pushing it onto the regret stack. */ regret(token) { if (++regretp >= REGDEP) panic("Too many regrets"); regretstack[regretp] = token; lexstring[STRINGLEN-1] = '\0'; stringstack[regretp] = savestr(lexstring); numberstack[regretp] = lexnumber; } /* * Reset all the scanner global variables. */ scaninit() { regretp = -1; } /* * Find the first message whose flags & m == f and return * its message number. */ first(f, m) { register int mesg; register struct message *mp; mesg = dot - &message[0]; mesg++; for (mp = dot; mp < &message[msgCount]; mp++) { if ((mp->m_flag & m) == f) return(mesg); mesg++; } mesg = dot - &message[0]; for (mp = dot-1; mp >= &message[0]; mp--) { if ((mp->m_flag & m) == f) return(mesg); mesg--; } return(NULL); } /* * See if the passed name sent the passed message number. Return true * if so. */ sender(str, mesg) char *str; { register struct message *mp; mp = &message[mesg-1]; return(!strcmp(nameof(mp), str)); } /* * Mark the named message by setting its mark bit. */ mark(mesg) { register int i; i = mesg; if (i < 1 || i > msgCount) panic("Bad message number to mark"); message[i-1].m_flag |= MMARK; } /* * Unmark the named message. */ unmark(mesg) { register int i; i = mesg; if (i < 1 || i > msgCount) panic("Bad message number to unmark"); message[i-1].m_flag &= ~MMARK; } /* * Return the message number corresponding to the passed meta character. */ metamess(meta, f) { register int c, m; register struct message *mp; c = meta; switch (c) { case '^': /* * First 'good' message left. */ for (mp = &message[0]; mp < &message[msgCount]; mp++) if ((mp->m_flag & MDELETED) == f) return(mp - &message[0] + 1); printf("No applicable messages\n"); return(-1); case '$': /* * Last 'good message left. */ for (mp = &message[msgCount-1]; mp >= &message[0]; mp--) if ((mp->m_flag & MDELETED) == f) return(mp - &message[0] + 1); printf("No applicable messages\n"); return(-1); case '.': /* * Current message. */ m = dot - &message[0] + 1; if ((dot->m_flag & MDELETED) != f) { printf("%d: Inappropriate message\n", m); return(-1); } return(m); default: printf("Unknown metachar (%c)\n", c); return(-1); } }