1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <unistd.h>
4 #include "qconfirm.h"
5 #include "qconfirm_conf_get.h"
6 #include "qconfirm_id.h"
7 #include "error.h"
8 #include "sig.h"
9 #include "stralloc.h"
10 #include "strerr.h"
11 #include "sgetopt.h"
12 #include "buffer.h"
13 #include "env.h"
14 #include "seek.h"
15 #include "byte.h"
16 #include "str.h"
17 #include "open.h"
18 #include "getline.h"
19 
20 #define USAGE " [-va] [ mid ... ]"
21 #define VERSION "$Id: qconfirm-check-mid.c,v 1.10 2004/03/15 19:08:14 pape Exp $"
22 #define FATAL "qconfirm-check-mid: fatal: "
23 #define WARNING "qconfirm-check-mid: warning: "
24 #define INFO "qconfirm-check-mid: info: "
25 
26 const char *progname;
27 
usage()28 void usage() { strerr_die4x(111, "usage: ", progname, USAGE, "\n"); }
die_nomem()29 void die_nomem() { strerr_die2x(111, FATAL, "out of memory."); }
fatal(char * m0,char * m1)30 void fatal(char *m0, char *m1) { strerr_die4sys(111, FATAL, m0, m1, ": "); }
warn(char * m0,char * m1)31 void warn(char *m0, char *m1) {
32   strerr_warn4(WARNING, m0, m1, ": ", &strerr_sys);
33 }
info(char * m0,char * m1)34 void info(char *m0, char *m1) {
35   buffer_puts(buffer_1, INFO); buffer_puts(buffer_1, m0);
36   buffer_puts(buffer_1, ": "); buffer_puts(buffer_1, m1);
37   buffer_putsflush(buffer_1, "\n");
38 }
die(int rc)39 void die(int rc) {
40   if (seek_begin(0) == -1) fatal("unable to seek: ", "stdin");
41   _exit(rc);
42 }
43 
44 unsigned int accept =0;
45 unsigned int verbose =0;
46 char *sender;
47 char *qconfirm_dir;
48 char *qconfirm_mid;
49 char **mids;
50 stralloc line ={0};
51 stralloc id ={0};
52 stralloc fn ={0};
53 
midmatch(void)54 const char *midmatch(void) {
55   char *s =line.s;
56   int slen =line.len;
57   int len;
58   int i;
59   char **m;
60   char *p;
61 
62   while (slen && (i =byte_chr(s, slen, '>')) < slen) {
63     if (*qconfirm_mid) {
64       p =qconfirm_mid;
65       for(;;) {
66 	if (! (len =str_chr(p, ' '))) break;
67 	if (byte_diff(p, len, s +i -len) == 0) {
68 	  p[len] =0;
69 	  return(p);
70 	}
71 	if (p[len] == 0) break;
72 	p +=len +1;
73       }
74     }
75     for (m =mids; m && *m; ++m) {
76       len =str_len(*m);
77       if (len > i) continue;
78       if (byte_diff(*m, len, s +i -len) == 0) return(*m);
79     }
80     ++i; s +=i; slen -=i;
81   }
82   return(0);
83 }
84 
accept_sender(void)85 void accept_sender(void) {
86   int fd;
87 
88   if (address2id(&id, sender) == -1) die_nomem();
89   if (! stralloc_copys(&fn, qconfirm_dir)) die_nomem();
90   if (! stralloc_cats(&fn, "/ok/")) die_nomem();
91   if (! stralloc_cat(&fn, &id)) die_nomem();
92   if ((fd =open_trunc(fn.s)) == -1)
93     warn("unable to create: ", fn.s);
94   else
95     if (verbose) info("accept", sender);
96   close(fd);
97 }
98 
main(int argc,char ** argv)99 int main(int argc, char **argv) {
100   int opt;
101   int i;
102   unsigned char x;
103   const char *m;
104   char *h =0;
105   char *p;
106 
107   progname =*argv;
108   umask(0177);
109   sig_ignore(sig_pipe);
110 
111   qconfirm_dir =env_get("QCONFIRM_DIR");
112   qconfirm_mid =env_get("QCONFIRM_MID");
113 
114   while ((opt =getopt(argc, (const char **)argv, "Vav")) != opteof) {
115     switch(opt) {
116     case 'a': accept =1; break;
117     case 'v': verbose =1; break;
118     case 'V': strerr_warn1(VERSION, 0);
119     case '?': usage();
120     }
121   }
122   argv +=optind;
123 
124   /* lowercase mids */
125   for(mids =argv; *mids; ++mids)
126     for (i =0; (*mids)[i]; ++i) {
127       x =(*mids)[i] -'A';
128       if (x <= 'Z' -'A') (*mids)[i] =x +'a';
129     }
130   mids =argv;
131 
132   sender =env_get("SENDER");
133   if (! sender)
134     strerr_die2x(100, FATAL, "environment variable SENDER not set.\n");
135   if (! qconfirm_dir) qconfirm_dir =QCONFIRMDIR;
136   if (! qconfirm_mid)
137     qconfirm_mid =conf_get_dflt(qconfirm_dir, "QCONFIRM_MID", "");
138   if (! qconfirm_mid) fatal("unable to read config: ", "QCONFIRM_MID");
139   /* lowercase QCONFIRM_MID */
140   for (i =0; qconfirm_mid[i]; ++i) {
141     x =qconfirm_mid[i] -'A';
142     if (x <= 'Z' -'A') qconfirm_mid[i] =x +'a';
143   }
144 
145   while ((i =getline(buffer_0, &line)) > 0) {
146     if ((i == 1) && (line.s[0] == '\n')) break; /* end of headers */
147     /* lowercase line */
148     for (i =0; i < line.len; ++i) {
149       x =line.s[i] -'A';
150       if (x <= 'Z' -'A') line.s[i] =x +'a';
151     }
152     if ((line.s[0] == ' ') || (line.s[0] == '\t')) {
153       if (h && (m =midmatch())) {
154 	info(h, (char*)m);
155 	if (accept) accept_sender();
156 	die(0);
157       }
158       continue;
159     }
160     else h =0;
161     if ((line.len > 13) && str_start(line.s, "in-reply-to")) {
162       for (p =line.s +11; (*p == ' ') || (*p == '\t'); ++p) ;
163       if (*p != ':') continue;
164       h ="in-reply-to";
165       if ((m =midmatch())) {
166 	info(h, (char*)m);
167 	if (accept) accept_sender();
168 	die(0);
169       }
170     }
171     if ((line.len > 12) && str_start(line.s, "references")) {
172       for (p =line.s +10; (*p == ' ') || (*p == '\t'); ++p) ;
173       if (*p != ':') continue;
174       h ="references";
175       if ((m =midmatch())) {
176 	info(h, (char*)m);
177 	if (accept) accept_sender();
178 	die(0);
179       }
180     }
181   }
182   if (i == -1) die_nomem();
183   if (verbose) info("unknown", "no known references");
184   die(100);
185   return(100);
186 }
187