14 #include "gen_alloc.h"
15 #include "gen_allocdefs.h"
16 #include "headerbody.h"
24 void die() { _exit(100); }
25 void die_temp() { _exit(111); }
27 substdio_putsflush(subfderr
,"qlist: fatal: out of memory\n"); die_temp(); }
29 substdio_putsflush(subfderr
,"qlist: fatal: unable to fork\n"); die_temp(); }
31 substdio_putsflush(subfderr
,"qlist: fatal: unable to open lock file\n"); die_temp(); }
33 substdio_putsflush(subfderr
,"qlist: fatal: I don't reply to bounces\n"); die(); }
35 substdio_putsflush(subfderr
,"qlist: fatal: sorry, I'm not allowed to use that address\n"); die(); }
37 substdio_putsflush(subfderr
,"qlist: fatal: permanent qmail-queue error\n"); die(); }
39 substdio_putsflush(subfderr
,"qlist: fatal: temporary qmail-queue error\n"); die_temp(); }
41 substdio_putsflush(subfderr
,
42 "qlist: usage: qlist user-list@host user-list-request@host .qmail-list .qmail-list-request .qtemp-list owner [moreinfo]\n"); die(); }
44 if (errno
== error_nomem
) die_nomem();
45 substdio_putsflush(subfderr
,"qlist: fatal: read error\n"); die_temp(); }
46 void doordie(sa
,r
) stralloc
*sa
; int r
; {
47 if (r
== 1) return; if (r
== -1) die_nomem();
48 substdio_putsflush(subfderr
,"qlist: fatal: unable to parse this: ");
49 substdio_putflush(subfderr
,sa
->s
,sa
->len
); die(); }
51 int subjectaction
= 0;
69 stralloc safrom
= {0};
72 int rwfrom(addr
) token822_alloc
*addr
; { token822_reverse(addr
);
73 if (token822_unquote(&safrom
,addr
) != 1) die_nomem();
74 token822_reverse(addr
); return 1; }
75 int rwrt(addr
) token822_alloc
*addr
; { token822_reverse(addr
);
76 if (token822_unquote(&sart
,addr
) != 1) die_nomem();
77 token822_reverse(addr
); return 1; }
79 GEN_ALLOC_typedef(saa
,stralloc
,sa
,len
,a
)
80 GEN_ALLOC_readyplus(saa
,stralloc
,sa
,len
,a
,i
,n
,x
,10,saa_readyplus
)
81 static stralloc sauninit
= {0}; saa savedh
= {0};
82 void savedh_append(h
) stralloc
*h
; {
83 if (!saa_readyplus(&savedh
,1)) die_nomem(); savedh
.sa
[savedh
.len
] = sauninit
;
84 if (!stralloc_copy(savedh
.sa
+ savedh
.len
,h
)) die_nomem(); ++savedh
.len
; }
85 void savedh_print() { int i
; for (i
= 0;i
< savedh
.len
;++i
)
86 qmail_put(&qqt
,savedh
.sa
[i
].s
,savedh
.sa
[i
].len
); }
93 { if (!stralloc_0(&sart
)) die_nomem(); target
= sart
.s
; }
95 { if (!stralloc_0(&safrom
)) die_nomem(); target
= safrom
.s
; }
99 for (i
= 0;target
[i
];++i
)
100 if (target
[i
] == '\n')
102 if (i
> ADDRLIMIT
) die_badaddr();
103 if (str_equal(target
,"")) die_boing();
104 if (str_equal(target
,"#@[]")) die_boing();
106 if (qmail_open(&qqt
) == -1) die_fork();
108 qmail_puts(&qqt
,dtline
);
111 qmail_puts(&qqt
,"\n***** Text inserted by ");
112 qmail_puts(&qqt
,requestathost
);
115 * Hi! This is the qlist program. I'm handling subscriptions for the\n\
117 qmail_puts(&qqt
,listathost
);
118 qmail_puts(&qqt
," mailing list.\n\
122 qmail_puts(&qqt
,"* ");
123 qmail_puts(&qqt
,moreinfo
);
124 qmail_puts(&qqt
,"\n*\n");
126 qmail_puts(&qqt
,"* My human owner is ");
127 qmail_puts(&qqt
,owner
);
128 qmail_puts(&qqt
,".\n\
130 * To the recipient: This message was sent to me on your behalf. (Your\n\
131 * address was listed in the Reply-To or From field.) For security,\n\
132 * I'm forwarding this message to you, along with my notes.\n\
134 * Anyway, to subscribe, send me an empty message. To unsubscribe, send me\n\
135 * a message with the word UNSUBSCRIBE at the beginning of a line. Remember,\n\
137 qmail_puts(&qqt
,requestathost
);
138 qmail_puts(&qqt
,".\n\
140 * Now I'll look for requests inside this message...\n\
145 substdio subin
; char subinbuf
[SUBSTDIO_INSIZE
];
146 substdio subout
; char suboutbuf
[SUBSTDIO_OUTSIZE
];
147 stralloc subline
= {0};
148 void subscribe(flagadd
)
158 if (lock_ex(fdlock
) == -1) goto bad
;
159 fdin
= open_read(qmaillist
);
160 if (fdin
== -1) goto badlock
;
161 fdout
= open_trunc(qtemplist
);
162 if (fdout
== -1) goto badinlock
;
163 if (chmod(qtemplist
,0700) == -1) goto badoutinlock
;
167 substdio_fdbuf(&subin
,read
,fdin
,subinbuf
,sizeof(subinbuf
));
168 substdio_fdbuf(&subout
,write
,fdout
,suboutbuf
,sizeof(suboutbuf
));
171 if (getln(&subin
,&subline
,&match
,'\n') == -1) goto badoutinlock
;
172 if (!match
) break; /* goodbye partial lines */
173 if (subline
.len
== str_len(target
) + 2)
174 if (!str_diffn(subline
.s
+ 1,target
,subline
.len
- 2))
175 if (subline
.s
[0] == '&')
181 if (substdio_put(&subout
,subline
.s
,subline
.len
) == -1) goto badoutinlock
;
184 if (flagadd
&& !flagwasthere
)
186 if (substdio_puts(&subout
,"&") == -1) goto badoutinlock
;
187 if (substdio_puts(&subout
,target
) == -1) goto badoutinlock
;
188 if (substdio_puts(&subout
,"\n") == -1) goto badoutinlock
;
190 if (substdio_flush(&subout
) == -1) goto badoutinlock
;
194 if (rename(qtemplist
,qmaillist
) == -1) goto badlock
;
195 if (chmod(qmaillist
,0500) == -1) goto badlock
;
199 qmail_puts(&qqt
,"***** Text inserted by ");
200 qmail_puts(&qqt
,requestathost
);
201 qmail_puts(&qqt
,"\n*\n* ");
205 qmail_puts(&qqt
,"Acknowledgment: ");
206 qmail_puts(&qqt
,target
);
207 qmail_puts(&qqt
," was already a subscriber.\n");
211 qmail_puts(&qqt
,"Acknowledgment: ");
212 qmail_puts(&qqt
,target
);
213 qmail_puts(&qqt
," is now a subscriber.\n");
218 qmail_puts(&qqt
,"Acknowledgment: ");
219 qmail_puts(&qqt
,target
);
220 qmail_puts(&qqt
," is no longer a subscriber.\n");
224 qmail_puts(&qqt
,"Hmmm, I don't see ");
225 qmail_puts(&qqt
,target
);
226 qmail_puts(&qqt
," on the subscription list.\n* I'll let my owner know.\n");
228 qmail_puts(&qqt
,"*\n*****\n");
231 badoutinlock
: close(fdout
);
232 badinlock
: close(fdin
);
233 badlock
: lock_un(fdlock
);
235 qmail_puts(&qqt
,"***** Text inserted by ");
236 qmail_puts(&qqt
,requestathost
);
237 qmail_puts(&qqt
,"\n*\n\
238 * Oh no! Trouble making the new list. I'll let my owner know.\n\
243 void dobody(h
) stralloc
*h
;
245 qmail_put(&qqt
,h
->s
,h
->len
);
246 if (case_starts(h
->s
,"subs")) subscribe(1);
247 if (case_starts(h
->s
,"unsu")) subscribe(0);
250 stralloc hfbuf
= {0};
251 token822_alloc hfin
= {0};
252 token822_alloc hfrewrite
= {0};
253 token822_alloc hfaddr
= {0};
255 void doheaderfield(h
)
259 switch(hfield_known(h
->s
,h
->len
))
261 case H_CONTENTLENGTH
: /* SVR4 silliness */
263 case H_CONTENTTRANSFERENCODING
: /* A-bombs 4.2.1.5.2 is idiotic */
266 doordie(h
,token822_parse(&hfin
,h
,&hfbuf
));
267 doordie(h
,token822_addrlist(&hfrewrite
,&hfaddr
,&hfin
,rwfrom
));
270 doordie(h
,token822_parse(&hfin
,h
,&hfbuf
));
271 doordie(h
,token822_addrlist(&hfrewrite
,&hfaddr
,&hfin
,rwrt
));
274 x
= h
->s
+ hfield_skipname(h
->s
,h
->len
);
275 if (!case_diffb(x
,4,"subs")) subjectaction
= 1;
276 if (!case_diffb(x
,4,"unsu")) subjectaction
= 2;
288 if (!(listathost
= argv
[1])) die_usage();
289 if (!(requestathost
= argv
[2])) die_usage();
290 if (!(qmaillist
= argv
[3])) die_usage();
291 if (!(qmailrequest
= argv
[4])) die_usage();
292 if (!(qtemplist
= argv
[5])) die_usage();
293 if (!(owner
= argv
[6])) die_usage();
295 if (!(returnpath
= env_get("NEWSENDER"))) die_usage();
296 if (!(dtline
= env_get("DTLINE"))) die_usage();
298 fdlock
= open_append(qmailrequest
);
299 if (fdlock
== -1) die_nolock();
302 if (headerbody(subfdin
,doheaderfield
,finishheader
,dobody
) == -1) die_read();
305 qmail_puts(&qqt
,"***** Text inserted by ");
306 qmail_puts(&qqt
,requestathost
);
307 qmail_puts(&qqt
,"\n*\n* ");
311 Hmmm, no commands? Let me check the Subject line...\n*\n*****\n");
312 subscribe(subjectaction
== 1);
317 I didn't see any commands. I presume this is a subscription request.\n\
323 qmail_from(&qqt
,returnpath
);
324 qmail_to(&qqt
,owner
);
325 qmail_to(&qqt
,target
);
327 switch(qmail_close(&qqt
))
330 case QMAIL_TOOLONG
: die_qqperm();
331 default: die_qqtemp();