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