Expanded PATHSIZE to 100, a more reasonable size
[unix-history] / usr / src / usr.bin / mail / list.c
index fe43a40..7b4c9db 100644 (file)
@@ -9,7 +9,7 @@
  * Message list handling.
  */
 
  * Message list handling.
  */
 
-static char *SccsId = "@(#)list.c      1.1 %G%";
+static char *SccsId = "@(#)list.c      2.1 %G%";
 
 /*
  * Convert the user string of message numbers and
 
 /*
  * Convert the user string of message numbers and
@@ -41,15 +41,48 @@ getmsglist(buf, vector, flags)
  * on error.
  */
 
  * on error.
  */
 
+/*
+ * Bit values for colon modifiers.
+ */
+
+#define        CMNEW           01              /* New messages */
+#define        CMOLD           02              /* Old messages */
+#define        CMUNREAD        04              /* Unread messages */
+#define        CMDELETED       010             /* Deleted messages */
+#define        CMREAD          020             /* Read messages */
+
+/*
+ * The following table describes the letters which can follow
+ * the colon and gives the corresponding modifier bit.
+ */
+
+struct coltab {
+       char    co_char;                /* What to find past : */
+       int     co_bit;                 /* Associated modifier bit */
+       int     co_mask;                /* m_status bits to mask */
+       int     co_equal;               /* ... must equal this */
+} coltab[] = {
+       'n',            CMNEW,          MNEW,           MNEW,
+       'o',            CMOLD,          MNEW,           0,
+       'u',            CMUNREAD,       MREAD,          0,
+       'd',            CMDELETED,      MDELETED,       MDELETED,
+       'r',            CMREAD,         MREAD,          MREAD,
+       0,              0,              0,              0
+};
+
+static int     lastcolmod;
+
 markall(buf, f)
        char buf[];
 {
        register char **np;
        register int i;
 markall(buf, f)
        char buf[];
 {
        register char **np;
        register int i;
+       register struct message *mp;
        char *namelist[NMLSIZE], *bufp;
        char *namelist[NMLSIZE], *bufp;
-       int tok, beg, mc, star, other, valdot;
+       int tok, beg, mc, star, other, valdot, colmod, colresult;
 
        valdot = dot - &message[0] + 1;
 
        valdot = dot - &message[0] + 1;
+       colmod = 0;
        for (i = 1; i <= msgCount; i++)
                unmark(i);
        bufp = buf;
        for (i = 1; i <= msgCount; i++)
                unmark(i);
        bufp = buf;
@@ -119,7 +152,17 @@ number:
                                return(-1);
                        }
                        other++;
                                return(-1);
                        }
                        other++;
-                       *np++ = savestr(lexstring);
+                       if (lexstring[0] == ':') {
+                               colresult = evalcol(lexstring[1]);
+                               if (colresult == 0) {
+                                       printf("Unknown colon modifier \"%s\"\n",
+                                           lexstring);
+                                       return(-1);
+                               }
+                               colmod |= colresult;
+                       }
+                       else
+                               *np++ = savestr(lexstring);
                        break;
 
                case TDOLLAR:
                        break;
 
                case TDOLLAR:
@@ -140,6 +183,7 @@ number:
                }
                tok = scan(&bufp);
        }
                }
                tok = scan(&bufp);
        }
+       lastcolmod = colmod;
        *np = NOSTR;
        mc = 0;
        if (star) {
        *np = NOSTR;
        mc = 0;
        if (star) {
@@ -161,7 +205,7 @@ number:
         * if any user names were given.
         */
 
         * if any user names were given.
         */
 
-       if (np > namelist && mc == 0)
+       if ((np > namelist || colmod != 0) && mc == 0)
                for (i = 1; i <= msgCount; i++)
                        if ((message[i-1].m_flag & (MSAVED|MDELETED)) == f)
                                mark(i);
                for (i = 1; i <= msgCount; i++)
                        if ((message[i-1].m_flag & (MSAVED|MDELETED)) == f)
                                mark(i);
@@ -174,9 +218,17 @@ number:
        if (np > namelist) {
                for (i = 1; i <= msgCount; i++) {
                        for (mc = 0, np = &namelist[0]; *np != NOSTR; np++)
        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 (**np == '/') {
+                                       if (matchsubj(*np, i)) {
+                                               mc++;
+                                               break;
+                                       }
+                               }
+                               else {
+                                       if (sender(*np, i)) {
+                                               mc++;
+                                               break;
+                                       }
                                }
                        if (mc == 0)
                                unmark(i);
                                }
                        if (mc == 0)
                                unmark(i);
@@ -201,6 +253,54 @@ number:
                        return(-1);
                }
        }
                        return(-1);
                }
        }
+
+       /*
+        * If any colon modifiers were given, go through and
+        * unmark any messages which do not satisfy the modifiers.
+        */
+
+       if (colmod != 0) {
+               for (i = 1; i <= msgCount; i++) {
+                       register struct coltab *colp;
+
+                       mp = &message[i - 1];
+                       for (colp = &coltab[0]; colp->co_char; colp++)
+                               if (colp->co_bit & colmod)
+                                       if ((mp->m_flag & colp->co_mask)
+                                           != colp->co_equal)
+                                               unmark(i);
+                       
+               }
+               for (mp = &message[0]; mp < &message[msgCount]; mp++)
+                       if (mp->m_flag & MMARK)
+                               break;
+               if (mp >= &message[msgCount]) {
+                       register struct coltab *colp;
+
+                       printf("No messages satisfy");
+                       for (colp = &coltab[0]; colp->co_char; colp++)
+                               if (colp->co_bit & colmod)
+                                       printf(" :%c", colp->co_char);
+                       printf("\n");
+                       return(-1);
+               }
+       }
+       return(0);
+}
+
+/*
+ * Turn the character after a colon modifier into a bit
+ * value.
+ */
+evalcol(col)
+{
+       register struct coltab *colp;
+
+       if (col == 0)
+               return(lastcolmod);
+       for (colp = &coltab[0]; colp->co_char; colp++)
+               if (colp->co_char == col)
+                       return(colp->co_bit);
        return(0);
 }
 
        return(0);
 }
 
@@ -441,10 +541,53 @@ sender(str, mesg)
        register char *cp;
 
        mp = &message[mesg-1];
        register char *cp;
 
        mp = &message[mesg-1];
-       cp = nameof(mp);
+       cp = nameof(mp, 0);
        return(icequal(cp, str));
 }
 
        return(icequal(cp, str));
 }
 
+/*
+ * See if the given string matches inside the subject field of the
+ * given message.  For the purpose of the scan, we ignore case differences.
+ * If it does, return true.  The string search argument is assumed to
+ * have the form "/search-string."  If it is of the form "/," we use the
+ * previous search string.
+ */
+
+char lastscan[128];
+
+matchsubj(str, mesg)
+       char *str;
+{
+       register struct message *mp;
+       register char *cp, *cp2, *backup;
+
+       str++;
+       if (strlen(str) == 0)
+               str = lastscan;
+       else
+               strcpy(lastscan, str);
+       mp = &message[mesg-1];
+       
+       /*
+        * Now look, ignoring case, for the word in the string.
+        */
+
+       cp = str;
+       cp2 = hfield("subject", mp);
+       if (cp2 == NOSTR)
+               return(0);
+       backup = cp2;
+       while (*cp2) {
+               if (*cp == 0)
+                       return(1);
+               if (raise(*cp++) != raise(*cp2++)) {
+                       cp2 = ++backup;
+                       cp = str;
+               }
+       }
+       return(*cp == 0);
+}
+
 /*
  * Mark the named message by setting its mark bit.
  */
 /*
  * Mark the named message by setting its mark bit.
  */