1 #include <unistd.h>
2 #include "stralloc.h"
3 #include "str.h"
4 #include "byte.h"
5 #include "case.h"
6 #include "readwrite.h"
7 #include "substdio.h"
8 #include "subfd.h"
9 #include "getln.h"
10 #include "strerr.h"
11 #include "messages.h"
12 #include "mime.h"
13 #include "die.h"
14 
15 const char FATAL[] = "ezmlm-weed: fatal: ";
16 const char USAGE[] =
17 "ezmlm-weed: usage: ezmlm-weed";
18 
19 static const char warn1[] = "    **********************************************";
20 static const char warn2[] = "    **      THIS IS A WARNING MESSAGE ONLY      **";
21 static const char warn3[] = "    **  YOU DO NOT NEED TO RESEND YOUR MESSAGE  **";
22 static const char warn4[] = "    **********************************************";
23 
get(stralloc * sa)24 static void get(stralloc *sa)
25 {
26   int match;
27   if (gethdrln(subfdin,sa,&match,'\n') == -1)
28     strerr_die2sys(111,FATAL,MSG(ERR_READ_INPUT));
29   if (!match) _exit(0);
30 }
31 
32 static stralloc line = {0};
33 static stralloc boundary = {0};
34 
isboundary(void)35 static int isboundary(void)
36 /* returns 1 if line.len contains the mime bondary, 0 otherwise */
37 {
38     if (line.s[0] == '-' && line.s[1] == '-' && line.len >= boundary.len + 3)
39       if (!byte_diff(line.s + 2,boundary.len,boundary.s))	/* boundary */
40         return 1;
41     return 0;
42 }
43 
main(void)44 int main(void)
45 {
46   stralloc line1 = {0};
47   stralloc line2 = {0};
48   stralloc line3 = {0};
49   stralloc line4 = {0};
50   stralloc line5 = {0};
51   stralloc line6 = {0};
52   stralloc line7 = {0};
53   stralloc line8 = {0};
54   stralloc dsnline = {0};
55 
56   int flagmds = 0;
57   int flagsw = 0;
58   int flagsr = 0;
59   int flagas = 0;
60   int flagbw = 0;
61   int flagdsn = 0;
62 
63   unsigned int i,j;
64 
65   for (;;) {
66     get(&line);
67     if (line.len == 1) break;
68     if (stralloc_starts(&line,"Subject: success notice"))
69       _exit(99);
70     if (stralloc_starts(&line,"Subject: deferral notice"))
71       _exit(99);
72     if (stralloc_starts(&line,"Precedence: bulk"))
73       _exit(99);
74     if (stralloc_starts(&line,"Precedence: junk"))
75       _exit(99);
76     if (stralloc_starts(&line,"Auto-Submitted:"))
77       _exit(99);
78     /* Mailing list signatures */
79     if (stralloc_starts(&line,"Precedence: list"))
80       _exit(99);
81     if (stralloc_starts(&line,"Mailing-List:"))
82       _exit(99);
83     if (stralloc_starts(&line,"List-ID:"))
84       _exit(99);
85     if (stralloc_starts(&line,"X-Mailing-List:"))
86       _exit(99);
87     if (stralloc_starts(&line,"X-ML-Name:"))
88       _exit(99);
89     if (stralloc_starts(&line,"List-Help:"))
90       _exit(99);
91     if (stralloc_starts(&line,"List-Unsubscribe:"))
92       _exit(99);
93     if (stralloc_starts(&line,"List-Subscribe:"))
94       _exit(99);
95     if (stralloc_starts(&line,"List-Post:"))
96       _exit(99);
97     if (stralloc_starts(&line,"List-Owner:"))
98       _exit(99);
99     if (stralloc_starts(&line,"List-Archive:"))
100       _exit(99);
101 /* for Novell Groupwise */
102     if (stralloc_starts(&line,"Subject: Message status - delivered"))
103       _exit(99);
104     if (stralloc_starts(&line,"Subject: Message status - opened"))
105       _exit(99);
106     if (stralloc_starts(&line,"Subject: Out of Office AutoReply:"))
107       _exit(99);
108     /* Other autoresponders */
109     if (stralloc_starts(&line,"X-Amazon-Auto-Reply:"))
110       _exit(99);
111     if (stralloc_starts(&line,"X-Mailer: KANA Response"))
112       _exit(99);
113     if (stralloc_starts(&line,"Thread-Topic: AutoResponse"))
114       _exit(99);
115     if (stralloc_starts(&line,"Subject: AutoResponse -"))
116       _exit(99);
117 
118     if (stralloc_starts(&line,"From: Mail Delivery Subsystem <MAILER-DAEMON@"))
119       flagmds = 1;
120     if (stralloc_starts(&line,"Subject: Warning: could not send message"))
121       flagsw = 1;
122     if (stralloc_starts(&line,"Subject: Returned mail: warning: cannot send message"))
123       flagsr = 1;
124     if (stralloc_starts(&line,"Auto-Submitted: auto-generated (warning"))
125       flagas = 1;
126     if (case_startb(line.s,line.len,"Content-type: multipart/report")) {
127       concatHDR(line.s,line.len,&dsnline);
128     }
129   }			/* end of header */
130 
131   if (dsnline.len > 0) {	/* always only one recipient/action */
132     flagdsn = 0;	/* will be set for correct report type */
133     for (i=0; i < dsnline.len; i += 1+byte_chr(dsnline.s+i,dsnline.len-i,';')) {
134       while (dsnline.s[i] == ' ' || dsnline.s[i] == '\t')
135 	if (++i >= dsnline.len) break;
136       if (case_startb(dsnline.s + i,dsnline.len - i,"report-type=")) {
137 	i += 12;
138 	while (dsnline.s[i] ==' ' || dsnline.s[i] =='\t' || dsnline.s[i] =='"')
139 	  if (++i >= dsnline.len) break;
140 	if (case_startb(dsnline.s + i,dsnline.len - i,"delivery-status"))
141 	  flagdsn = 1;
142       } else if (case_startb(dsnline.s + i,dsnline.len - i,"boundary=")) {
143 	i += 9;
144 	while (dsnline.s[i] ==' ' || dsnline.s[i] =='\t')
145 	  if (++i >= dsnline.len) break;
146 	if (dsnline.s[i] == '"') {
147 	  if (++i >= dsnline.len) break;
148 	  j = i + byte_chr(dsnline.s + i,dsnline.len - i,'"');
149 	  if (j >= dsnline.len) break;
150 	} else {
151 	  j = i;
152 	  while (dsnline.s[j] !=' ' && dsnline.s[j] !='\t' &&
153 		dsnline.s[j] !=';')
154 	    if (++j >= dsnline.len) break;
155 	}				/* got boundary */
156 	if (!stralloc_copyb(&boundary,dsnline.s+i,j-i)) die_nomem();
157       }
158     }
159   }
160   if (flagdsn && boundary.len) {	/* parse DSN message */
161     get(&line);			/* if bad format we exit(0) via get() */
162     for (;;) {
163       if (isboundary()) {
164       if (line.len == boundary.len + 5 && line.s[line.len - 1] == '-'
165 		&& line.s[line.len - 2] == '-')
166         _exit(99);			/* end: not failure report */
167         get(&line);			/* Content-type */
168         if (case_startb(line.s,line.len,"content-type:")) {
169 	  i = 13;
170 	  while (line.s[i] == ' ' || line.s[i] == '\t')
171 		if (++i >= line.len) break;
172 	  if (case_startb(line.s+i,line.len-i,"message/delivery-status")) {
173 	    for (;;) {
174 	      get(&line);
175 	      if (isboundary()) break;
176 	      if (case_startb(line.s,line.len,"action:")) {
177 	        i = 8;
178 	        while (line.s[i] == ' ' || line.s[i] == '\t')
179 		  if (++i >= line.len) break;
180 	        if (case_startb(line.s + i, line.len - i,"failed"))
181 		  _exit(0);	/* failure notice */
182 		else
183 		  _exit(99);	/* there shouldn't be more than 1 action */
184 	      }
185             }
186 	  }
187         }
188       } else
189 	get(&line);
190     }
191   }
192 
193   get(&line1);
194   get(&line2);
195   get(&line3);
196   get(&line4);
197   get(&line5);
198   get(&line6);
199   get(&line7);
200   get(&line8);
201 
202   if (stralloc_starts(&line1,"This is a MIME-encapsulated message"))
203   if (stralloc_starts(&line3,"--"))
204   if (stralloc_starts(&line5,warn1))
205   if (stralloc_starts(&line6,warn2))
206   if (stralloc_starts(&line7,warn3))
207   if (stralloc_starts(&line8,warn4))
208     flagbw = 1;
209 
210   if (stralloc_starts(&line1,warn1))
211   if (stralloc_starts(&line2,warn2))
212   if (stralloc_starts(&line3,warn3))
213   if (stralloc_starts(&line4,warn4))
214     flagbw = 1;
215 
216   if (flagmds && flagsw && flagas && flagbw) _exit(99);
217   if (flagmds && flagsr && flagbw) _exit(99);
218 
219   _exit(0);
220 }
221