1 #include <string.h>
2 #include <stdio.h>
3 #include <errno.h>
4 #include <stdlib.h>
5 #include <time.h>
6 #include <ctype.h>
7
8 #ifndef WIN32
9 #include <sys/time.h>
10 #include <unistd.h>
11 #endif
12
13 #include "send-mod.h"
14
HOOK_HANDLER(hook_tolist_sort)15 HOOK_HANDLER(hook_tolist_sort)
16 {
17 if (!LMAPI->get_bool("sort-tolist")) return HOOK_RESULT_OK;
18
19 LMAPI->sort_tolist();
20 return HOOK_RESULT_OK;
21 }
22
HOOK_HANDLER(hook_tolist_build_tolist)23 HOOK_HANDLER(hook_tolist_build_tolist)
24 {
25 char *extra_lists;
26
27 LMAPI->new_tolist();
28
29 LMAPI->add_from_list_all(LMAPI->get_string("list"));
30
31 if(LMAPI->get_bool("megalist"))
32 return HOOK_RESULT_OK;
33
34 /* Okay.. Heres' how we bounce to multiple lists */
35 extra_lists = strdup(LMAPI->get_string("cc-lists"));
36 if(extra_lists) {
37 char *l = strtok(extra_lists, ":");
38 while(l) {
39 if(LMAPI->list_valid(l)) {
40 LMAPI->add_from_list_all(l);
41 }
42 l = strtok(NULL,":");
43 }
44 }
45 free(extra_lists);
46
47 return(HOOK_RESULT_OK);
48 }
49
HOOK_HANDLER(hook_tolist_remove_vacationers)50 HOOK_HANDLER(hook_tolist_remove_vacationers)
51 {
52 LMAPI->remove_flagged_all_prilist("VACATION",LMAPI->get_string("list"));
53 LMAPI->remove_flagged_all_prilist("DIAGNOSTIC",LMAPI->get_string("list"));
54
55 return(HOOK_RESULT_OK);
56 }
57
HOOK_HANDLER(hook_presend_check_moderate)58 HOOK_HANDLER(hook_presend_check_moderate)
59 {
60 if (LMAPI->get_bool("moderated")) {
61 const char *tempchk;
62 struct list_user user;
63
64 if (LMAPI->user_find_list(LMAPI->get_string("list"),LMAPI->get_string("realsender"),
65 &user)) {
66 if (LMAPI->user_hasflag(&user,"ADMIN")) {
67 if (LMAPI->get_bool("admin-approvepost")) {
68 LMAPI->set_var("moderated-approved-by",LMAPI->get_string("realsender"),VAR_GLOBAL);
69 }
70 }
71 if (LMAPI->user_hasflag(&user,"PREAPPROVE")) {
72 LMAPI->set_var("moderated-approved-by",LMAPI->get_string("realsender"),VAR_GLOBAL);
73 }
74 if(LMAPI->user_hasflag(&user, "MODERATOR")) {
75 if (LMAPI->get_bool("moderator-approvepost")) {
76 LMAPI->set_var("moderated-approved-by",LMAPI->get_string("realsender"),VAR_GLOBAL);
77 }
78 }
79 }
80
81 tempchk = LMAPI->get_var("moderated-approved-by");
82 if (!tempchk) {
83 LMAPI->make_moderated_post("Post to moderated list.");
84 return HOOK_RESULT_STOP;
85 }
86 }
87 return (HOOK_RESULT_OK);
88 }
89
HOOK_HANDLER(hook_presend_check_modpost)90 HOOK_HANDLER(hook_presend_check_modpost)
91 {
92 /* No point in checking if the list is moderated, eh? */
93 if (!LMAPI->get_bool("moderated")) {
94 const char *tempchk;
95 struct list_user user;
96
97 if (LMAPI->user_find_list(LMAPI->get_string("list"),LMAPI->get_string("realsender"),
98 &user)) {
99 if (LMAPI->user_hasflag(&user,"MODPOST")) {
100 tempchk = LMAPI->get_var("moderated-approved-by");
101 if (!tempchk) {
102 LMAPI->make_moderated_post("Post by a user set MODPOST.");
103 return HOOK_RESULT_STOP;
104 }
105 }
106 }
107
108 }
109 return (HOOK_RESULT_OK);
110 }
111
112
HOOK_HANDLER(hook_presend_check_closed)113 HOOK_HANDLER(hook_presend_check_closed)
114 {
115 if (LMAPI->get_var("moderated-approved-by")) return HOOK_RESULT_OK;
116
117 if (LMAPI->get_bool("closed-post")) {
118 struct list_user user;
119 int founduser;
120 char userfilepath[BIG_BUF]; /* Changed from SMALL_BUF to BIG_BUF due to listdir_file */
121
122 LMAPI->listdir_file(userfilepath, LMAPI->get_string("list"), "users");
123
124 founduser = LMAPI->user_find_list(LMAPI->get_string("list"),LMAPI->get_string("fromaddress"),&user);
125
126 if (!founduser) {
127 founduser = LMAPI->user_find_list(LMAPI->get_string("list"),
128 LMAPI->get_string("fromaddress"),&user);
129 }
130
131 if (!founduser && LMAPI->get_bool("posting-acl")) {
132 char aclfilename[BIG_BUF];
133 FILE *aclfile;
134 char aclbuffer[BIG_BUF];
135
136 LMAPI->listdir_file(aclfilename,LMAPI->get_string("list"),
137 LMAPI->get_string("posting-acl-file"));
138
139 if (LMAPI->exists_file(aclfilename)) {
140
141 if ((aclfile = LMAPI->open_file(aclfilename,"r")) != NULL) {
142
143 while (LMAPI->read_file(aclbuffer, sizeof(aclbuffer), aclfile)) {
144
145 if (aclbuffer[strlen(aclbuffer) - 1] == '\n')
146 aclbuffer[strlen(aclbuffer) - 1] = 0;
147
148 if (LMAPI->match_reg(aclbuffer,
149 LMAPI->get_string("fromaddress")))
150 founduser = 1;
151
152 }
153
154 LMAPI->close_file(aclfile);
155
156 }
157
158 }
159
160 }
161
162 if (!founduser && LMAPI->get_var("union-lists")) {
163 char unions[64];
164 char *tptr, *tptr2;
165
166 LMAPI->log_printf(9,"Checking union lists...\n");
167
168 LMAPI->buffer_printf(unions, 64, "%.63s", LMAPI->get_var("union-lists"));
169
170 tptr = &unions[0];
171 tptr2 = strchr(tptr,':');
172 if (tptr2) *tptr2++ = 0;
173
174 while (!founduser && tptr) {
175 LMAPI->log_printf(9,"Checking '%s'...\n", tptr);
176
177 founduser = LMAPI->user_find_list(tptr,
178 LMAPI->get_string("fromaddress"), &user);
179
180 tptr = tptr2;
181
182 if (tptr) {
183 tptr2 = strchr(tptr,':');
184 if (tptr2) *tptr2++ = 0;
185 }
186 }
187 }
188
189 if (!founduser) {
190 const char *closedfile;
191 int usedefault;
192 char inbuffer[BIG_BUF];
193 const char *closedsubject;
194
195 closedfile = LMAPI->get_var("closed-file");
196 usedefault = 1;
197 closedsubject = LMAPI->get_var("closed-post-subject");
198
199 if (!closedsubject) {
200 LMAPI->buffer_printf(inbuffer, sizeof(inbuffer) - 1, "List '%s' closed to public posts", LMAPI->get_string("list"));
201 }
202 else {
203 LMAPI->buffer_printf(inbuffer, sizeof(inbuffer) - 1, "%s", closedsubject);
204 }
205 LMAPI->set_var("task-form-subject",&inbuffer[0],VAR_TEMP);
206
207 if (closedfile) {
208 LMAPI->listdir_file(inbuffer, LMAPI->get_string("list"),
209 closedfile);
210
211 usedefault = !LMAPI->send_textfile_expand_append(LMAPI->get_string("fromaddress"),&inbuffer[0],LMAPI->get_bool("moderate-include-queue"));
212 }
213
214 if(!LMAPI->get_bool("closed-post-blackhole")) {
215 LMAPI->clean_var("moderate-quiet",VAR_TEMP);
216 if (!usedefault)
217 LMAPI->set_var("moderate-quiet","yes",VAR_TEMP);
218 LMAPI->make_moderated_post("Non-member submission to closed-post list.");
219 LMAPI->clean_var("moderate-quiet",VAR_TEMP);
220 }
221 return HOOK_RESULT_STOP;
222 }
223 }
224 return (HOOK_RESULT_OK);
225 }
226
HOOK_HANDLER(hook_presend_check_outside)227 HOOK_HANDLER(hook_presend_check_outside)
228 {
229 struct list_user user;
230 int founduser;
231 char userfilepath[BIG_BUF]; /* Changed from SMALL_BUF to BIG_BUF due to listdir_file */
232
233 if (LMAPI->get_var("moderated-approved-by")) return HOOK_RESULT_OK;
234 if (LMAPI->get_bool("closed-post")) return HOOK_RESULT_OK;
235
236 LMAPI->listdir_file(userfilepath, LMAPI->get_string("list"), "users");
237
238 founduser = LMAPI->user_find_list(LMAPI->get_string("list"),LMAPI->get_string("fromaddress"),&user);
239
240 if (!founduser && LMAPI->get_var("union-lists")) {
241 char unions[64];
242 char *tptr, *tptr2;
243
244 LMAPI->log_printf(9,"Checking union lists...\n");
245
246 LMAPI->buffer_printf(unions, 64, "%.63s", LMAPI->get_var("union-lists"));
247
248 tptr = &unions[0];
249 tptr2 = strchr(tptr,':');
250 if (tptr2) *tptr2++ = 0;
251
252 while (!founduser && tptr) {
253 LMAPI->log_printf(9,"Checking '%s'...\n", tptr);
254
255 founduser = LMAPI->user_find_list(tptr,
256 LMAPI->get_string("fromaddress"), &user);
257
258 tptr = tptr2;
259
260 if (tptr) {
261 tptr2 = strchr(unions,':');
262 if (tptr2) *tptr2++ = 0;
263 }
264 }
265 }
266
267 if (!founduser) {
268 const char *outsidefile;
269 char inbuffer[BIG_BUF];
270
271 outsidefile = LMAPI->get_var("outside-file");
272
273 if (outsidefile) {
274 LMAPI->buffer_printf(inbuffer, sizeof(inbuffer) - 1, "Re: post to '%s'",
275 LMAPI->get_string("list"));
276
277 LMAPI->set_var("task-form-subject",&inbuffer[0],VAR_TEMP);
278
279 LMAPI->listdir_file(inbuffer, LMAPI->get_string("list"),
280 outsidefile);
281
282 LMAPI->send_textfile_expand(LMAPI->get_string("fromaddress"),
283 &inbuffer[0]);
284 }
285 LMAPI->clean_var("task-form-subject",VAR_TEMP);
286 }
287 return (HOOK_RESULT_OK);
288 }
289
290
HOOK_HANDLER(hook_presend_check_nopost)291 HOOK_HANDLER(hook_presend_check_nopost)
292 {
293 struct list_user user;
294 int founduser;
295
296 if (LMAPI->get_var("moderated-approved-by")) return HOOK_RESULT_OK;
297
298 founduser = LMAPI->user_find_list(LMAPI->get_string("list"),LMAPI->get_string("fromaddress"),&user);
299
300 if (founduser && LMAPI->user_hasflag(&user,"NOPOST")) {
301 const char *closedfile;
302 int usedefault;
303 char inbuffer[BIG_BUF];
304
305 closedfile = LMAPI->get_var("nopost-file");
306 usedefault = 1;
307
308 LMAPI->buffer_printf(inbuffer, sizeof(inbuffer) - 1, "Set NOPOST on list '%s'", LMAPI->get_string("list"));
309 LMAPI->set_var("task-form-subject",&inbuffer[0],VAR_TEMP);
310
311 if (closedfile) {
312 LMAPI->listdir_file(inbuffer, LMAPI->get_string("list"),
313 closedfile);
314
315 usedefault = !LMAPI->send_textfile_expand(LMAPI->get_string("fromaddress"),&inbuffer[0]);
316 }
317
318 if (usedefault) {
319 if(!LMAPI->task_heading(LMAPI->get_string("fromaddress")))
320 return HOOK_RESULT_FAIL;
321 LMAPI->smtp_body_text("Your post to list '");
322 LMAPI->smtp_body_text(LMAPI->get_string("list"));
323 LMAPI->smtp_body_line("' could not be processed.");
324 LMAPI->smtp_body_line("");
325 LMAPI->smtp_body_line("You are set NOPOST for this list. Users who are set NOPOST cannot");
326 LMAPI->smtp_body_line("post to the list. This flag is usually used for disciplinary reasons.");
327 LMAPI->smtp_body_line("");
328 LMAPI->smtp_body_line("Your post has been eaten. It was crunchy, and tasted good with");
329 LMAPI->smtp_body_line("ketchup.");
330 LMAPI->smtp_body_line("");
331 LMAPI->smtp_body_line("You may wish to contact a list owner if you are unsure why you are");
332 LMAPI->smtp_body_line("set NOPOST.");
333 LMAPI->task_ending();
334 }
335 return HOOK_RESULT_STOP;
336 }
337
338 return (HOOK_RESULT_OK);
339 }
340
341
HOOK_HANDLER(hook_final_send)342 HOOK_HANDLER(hook_final_send)
343 {
344 const char *sendas;
345
346 /* First thing, build the TO list so that we can know where we're going */
347 if(LMAPI->do_hooks("TOLIST") == HOOK_RESULT_FAIL)
348 return HOOK_RESULT_FAIL;
349
350 sendas = LMAPI->get_var("send-as");
351 if (!sendas) sendas = LMAPI->get_var("list-owner");
352 if (!sendas) sendas = LMAPI->get_var("listserver-admin");
353
354 if(!LMAPI->send_to_tolist(sendas, LMAPI->get_string("queuefile"), 1, 1,
355 LMAPI->get_bool("full-bounce"))) {
356 return HOOK_RESULT_FAIL;
357 }
358
359 if(LMAPI->do_hooks("AFTER") == HOOK_RESULT_FAIL)
360 return HOOK_RESULT_FAIL;
361 return HOOK_RESULT_OK;
362 }
363
HOOK_HANDLER(hook_presend_check_messageid)364 HOOK_HANDLER(hook_presend_check_messageid)
365 {
366 char buffer[BIG_BUF], buffer2[BIG_BUF];
367 FILE *infile, *messagefile;
368 time_t lasttime;
369 int inbody, gotit;
370 int docheck;
371
372 if (!LMAPI->get_bool("no-dupes"))
373 return HOOK_RESULT_OK;
374
375 docheck = 1;
376
377 /* If this has been approved, we don't need to dupecheck it. If an admin/moderator
378 has a mailer loop, they shouldn't be moderating anyway. */
379 if (LMAPI->get_var("moderated-approved-by"))
380 return HOOK_RESULT_OK;
381
382 infile = LMAPI->open_file(LMAPI->get_string("queuefile"), "r");
383 if (infile == NULL) {
384 return HOOK_RESULT_OK;
385 }
386
387 LMAPI->listdir_file(buffer, LMAPI->get_string("list"), "nodupes");
388
389 if ((messagefile = LMAPI->open_exclusive(buffer,"a+")) == NULL) {
390 LMAPI->close_file(infile);
391 return HOOK_RESULT_OK;
392 }
393 LMAPI->rewind_file(messagefile);
394
395 if(!LMAPI->read_file(buffer, sizeof(buffer), messagefile)) {
396 time(&lasttime);
397 LMAPI->write_file(messagefile,"%d\n",(int)lasttime);
398 docheck = 0;
399 } else {
400 time_t now;
401
402 time(&now);
403 lasttime = (time_t)atoi(buffer);
404
405 if (!LMAPI->get_bool("no-dupes-forever")) {
406 if ((now / 86400) != (lasttime / 86400)) {
407 LMAPI->rewind_file(messagefile);
408 LMAPI->truncate_file(messagefile, 0);
409 LMAPI->write_file(messagefile,"%d\n",(int)now);
410 docheck = 0;
411 }
412 }
413 }
414
415 inbody = 0; gotit = 0;
416
417 while(LMAPI->read_file(buffer, sizeof(buffer), infile) && !inbody) {
418 if (!strncasecmp(buffer,"Message-Id:",11)) {
419 gotit = 1;
420 break;
421 }
422 if (buffer[0] == '\n') inbody = 1;
423 }
424
425
426 if (!gotit) {
427 LMAPI->log_printf(1,"No message ID for message, unable to dupe-check.\n");
428 LMAPI->close_file(messagefile);
429 LMAPI->close_file(infile);
430 return HOOK_RESULT_OK;
431 }
432
433 if (!docheck) {
434 LMAPI->write_file(messagefile,"%s",buffer);
435 LMAPI->close_file(messagefile);
436 LMAPI->close_file(infile);
437 return HOOK_RESULT_OK;
438 }
439
440 gotit = 0;
441
442 while(LMAPI->read_file(buffer2, sizeof(buffer2), messagefile)) {
443 if (!strcasecmp(buffer2,buffer))
444 gotit = 1;
445 }
446
447 if (!gotit) {
448 /* We should now be situated at the end of the file */
449 LMAPI->write_file(messagefile,"%s",buffer);
450 LMAPI->close_file(messagefile);
451 LMAPI->close_file(infile);
452 return HOOK_RESULT_OK;
453 } else {
454 LMAPI->log_printf(0,"Received duplicate message, ignoring.\n");
455 LMAPI->close_file(infile);
456 return HOOK_RESULT_STOP;
457 }
458 }
459
HOOK_HANDLER(hook_presend_check_password)460 HOOK_HANDLER(hook_presend_check_password)
461 {
462 char buffer[BIG_BUF], outfilename[BIG_BUF];
463 FILE *infile, *outfile;
464 int gotpass;
465
466 LMAPI->log_printf(9,"In the password check...\n");
467
468 if (!LMAPI->get_var("post-password")) return HOOK_RESULT_OK;
469
470 gotpass = 0;
471
472 LMAPI->buffer_printf(outfilename, sizeof(outfilename) - 1, "%s.nukepass", LMAPI->get_string("queuefile"));
473
474 if (!(infile = LMAPI->open_file(LMAPI->get_string("queuefile"),"r"))) {
475 LMAPI->filesys_error(LMAPI->get_string("queuefile"));
476 return HOOK_RESULT_FAIL;
477 }
478
479 if (!(outfile = LMAPI->open_file(outfilename,"w"))) {
480 LMAPI->close_file(infile);
481 LMAPI->filesys_error(outfilename);
482 return HOOK_RESULT_FAIL;
483 }
484
485 while(LMAPI->read_file(buffer, sizeof(buffer), infile)) {
486 if (!strncasecmp(buffer,"X-posting-pass:",15) ||
487 !strncasecmp(buffer,"Password:",9)) {
488 const char *pass;
489 char *compare;
490
491 pass = LMAPI->get_string("post-password");
492
493 LMAPI->log_printf(5,"Checking posting password...\n");
494
495 if (!strncasecmp(buffer,"X-posting-pass:",15))
496 compare = &buffer[16];
497 else /* 'Password:' */
498 compare = &buffer[10];
499
500 if (strncmp(compare,pass,strlen(pass))) {
501 buffer[strlen(buffer) - 1] = 0;
502 LMAPI->log_printf(1, "Invalid password '%s' for list '%s'\n",
503 &buffer[15], LMAPI->get_string("list"));
504 LMAPI->close_file(outfile);
505 LMAPI->close_file(infile);
506 LMAPI->unlink_file(outfilename);
507 if (LMAPI->get_bool("password-failure-blackhole")) {
508 LMAPI->result_printf("Invalid password for posting to list '%s'.\n",
509 LMAPI->get_string("list"));
510 } else {
511 LMAPI->make_moderated_post("Incorrect password on password-restricted list.");
512 }
513 return HOOK_RESULT_STOP;
514 } else {
515 gotpass = 1;
516 }
517 } else {
518 LMAPI->write_file(outfile,"%s",buffer);
519 }
520 }
521 LMAPI->close_file(infile);
522 LMAPI->close_file(outfile);
523
524 if (!gotpass) {
525 const char *nopassfile = LMAPI->get_var("post-password-reject-file");
526 int usedefault = 1;
527
528 if (LMAPI->get_bool("password-failure-blackhole")) {
529 if (nopassfile) {
530 char inbuffer[BIG_BUF];
531 LMAPI->set_var("task-form-subject", "Posting rejected.", VAR_TEMP);
532 LMAPI->listdir_file(inbuffer, LMAPI->get_string("list"),
533 nopassfile);
534 usedefault = !LMAPI->send_textfile_expand(LMAPI->get_string("fromaddress"),inbuffer);
535 LMAPI->clean_var("task-form-subject", VAR_TEMP);
536 }
537
538 if (usedefault) {
539 LMAPI->result_printf("Sorry, you did not provide an X-posting-pass ");
540 LMAPI->result_printf("for list '%s'.\n", LMAPI->get_string("list"));
541 }
542
543 LMAPI->unlink_file(outfilename);
544 } else {
545 LMAPI->make_moderated_post("Post submitted to moderated list.");
546 }
547 return HOOK_RESULT_STOP;
548 } else {
549 LMAPI->log_printf(3,"Posting validated for list '%s'.\n",
550 LMAPI->get_string("list"));
551 LMAPI->replace_file(outfilename,LMAPI->get_string("queuefile"));
552 if (LMAPI->get_bool("password-implies-approved"))
553 LMAPI->set_var("moderated-approved-by",
554 LMAPI->get_string("realsender"), VAR_GLOBAL);
555 return HOOK_RESULT_OK;
556 }
557 }
558
HOOK_HANDLER(hook_presend_check_overquoting)559 HOOK_HANDLER(hook_presend_check_overquoting)
560 {
561 int quotepercent, quotelines;
562 int totallines;
563 int quotedlines;
564 int realquotedlines, tolerancelines;
565 int inbody, resetlines;
566 char buffer[BIG_BUF];
567 FILE *infile;
568
569 LMAPI->log_printf(9,"Overquoting check...\n");
570
571 if (!LMAPI->get_bool("quoting-limits"))
572 return HOOK_RESULT_OK;
573 if (LMAPI->get_var("moderated-approved-by"))
574 return HOOK_RESULT_OK;
575
576 quotepercent = LMAPI->get_number("quoting-max-percent");
577 quotelines = LMAPI->get_number("quoting-max-lines");
578 tolerancelines = LMAPI->get_number("quoting-tolerance-lines");
579
580 /* We can't do anything if they didn't set limits */
581 if (!quotepercent && !quotelines)
582 return HOOK_RESULT_OK;
583
584 resetlines = LMAPI->get_bool("quoting-line-reset");
585
586 if ((infile = LMAPI->open_file(LMAPI->get_string("queuefile"),"r")) ==
587 NULL) {
588 LMAPI->filesys_error(LMAPI->get_string("queuefile"));
589 return HOOK_RESULT_FAIL;
590 }
591
592 totallines = 0; quotedlines = 0; realquotedlines = 0;
593
594 inbody = 0;
595
596 while(LMAPI->read_file(buffer, sizeof(buffer), infile)) {
597 if (inbody) totallines++;
598 if (buffer[0] == '\n') inbody = 1;
599 if (buffer[0] == '>') {
600 /* We don't count sendmail escaping against them */
601 if (strncmp(&buffer[1],"From ",5)) {
602 quotedlines++;
603 realquotedlines++;
604 }
605 } else
606 if (buffer[0] == '|') {
607 quotedlines++;
608 realquotedlines++;
609 } else
610 if (resetlines && quotelines) {
611 /* If we reset after a block, AND if we haven't exceeded our
612 maximum already... */
613 if (quotedlines <= quotelines)
614 quotedlines = 0;
615 }
616 }
617
618 LMAPI->close_file(infile);
619
620 LMAPI->log_printf(9,"Overquoting: %d %d %d (%d or %d%% max)\n",
621 totallines, realquotedlines, quotedlines, quotelines,
622 quotepercent);
623
624 if (quotepercent && (tolerancelines ? totallines > tolerancelines : 1)) {
625 int percent;
626
627 percent = (realquotedlines * 100) / totallines;
628 LMAPI->log_printf(9,"Overquoting: %d percent (%d%% max)\n",
629 percent, quotepercent);
630
631 if (percent > quotepercent) {
632 char failure[BIG_BUF];
633 char overquotefile[BIG_BUF];
634
635 LMAPI->buffer_printf(failure, sizeof(failure) - 1,
636 "%d%% of message quoted (%d%% max allowed)",
637 percent, quotepercent);
638
639 LMAPI->buffer_printf(buffer, sizeof(buffer) - 1, "Overquoting: %s",
640 failure);
641
642 LMAPI->set_var("overquoting-reason",failure,VAR_TEMP);
643 LMAPI->listdir_file(overquotefile,LMAPI->get_string("list"),
644 LMAPI->get_string("overquote-file"));
645
646 /* We want the user to know their post was held because of
647 overquoting. */
648 LMAPI->set_var("moderate-force-notify","yes",VAR_TEMP);
649
650 if (LMAPI->send_textfile_expand_append(
651 LMAPI->get_string("realsender"), overquotefile,
652 LMAPI->get_bool("overquoting-include-queue")))
653 LMAPI->set_var("moderate-quiet","yes",VAR_TEMP);
654 LMAPI->make_moderated_post(buffer);
655 LMAPI->clean_var("moderate-quiet",VAR_TEMP);
656 LMAPI->clean_var("overquoting-reason",VAR_TEMP);
657 LMAPI->clean_var("moderate-force-notify",VAR_TEMP);
658 return HOOK_RESULT_STOP;
659 }
660 }
661
662 if (quotelines) {
663 if (quotedlines > quotelines) {
664 char failure[BIG_BUF];
665 char overquotefile[BIG_BUF];
666
667 LMAPI->buffer_printf(failure, sizeof(failure) - 1,
668 "%d lines quoted%s (%d max allowed)",
669 quotedlines, resetlines ? " in a block" : "", quotelines);
670
671 LMAPI->buffer_printf(buffer, sizeof(buffer) - 1, "Overquoting: %s",
672 failure);
673
674 /* We want the user to know their post was held because of
675 overquoting. */
676 LMAPI->set_var("moderate-force-notify","yes",VAR_TEMP);
677
678 LMAPI->set_var("overquoting-reason",failure,VAR_TEMP);
679 LMAPI->listdir_file(overquotefile,LMAPI->get_string("list"),
680 LMAPI->get_string("overquote-file"));
681 if (LMAPI->send_textfile_expand_append(
682 LMAPI->get_string("realsender"), overquotefile,
683 LMAPI->get_bool("overquoting-include-queue")))
684 LMAPI->set_var("moderate-quiet","yes",VAR_TEMP);
685 LMAPI->make_moderated_post(buffer);
686 LMAPI->clean_var("moderate-quiet",VAR_TEMP);
687 LMAPI->clean_var("overquoting-reason",VAR_TEMP);
688 LMAPI->clean_var("moderate-force-notify",VAR_TEMP);
689 return HOOK_RESULT_STOP;
690 }
691 }
692
693 return HOOK_RESULT_OK;
694 }
695
HOOK_HANDLER(hook_presend_check_bcc)696 HOOK_HANDLER(hook_presend_check_bcc)
697 {
698 FILE *queuefile;
699 char inputbuf[BIG_BUF];
700 int lastvalid;
701 int gotaddress;
702 const char *enforceto;
703
704 enforceto = LMAPI->get_var("enforced-addressing-to");
705
706 if (!enforceto)
707 return HOOK_RESULT_OK;
708 if (LMAPI->get_var("moderated-approved-by"))
709 return HOOK_RESULT_OK;
710
711 queuefile = LMAPI->open_file(LMAPI->get_string("queuefile"),"r");
712
713 if (queuefile == NULL) {
714 LMAPI->filesys_error(LMAPI->get_string("queuefile"));
715 return HOOK_RESULT_FAIL;
716 }
717
718 gotaddress = 0;
719 lastvalid = 0;
720
721 while(LMAPI->read_file(inputbuf, sizeof(inputbuf), queuefile) && !gotaddress) {
722 if (inputbuf[0] == '\n') break;
723
724 if (isspace((int)(inputbuf[0])) && lastvalid) {
725 if (LMAPI->strcasestr(inputbuf, enforceto)) gotaddress = 1;
726 } else lastvalid = 0;
727
728 if (strncasecmp(inputbuf,"To:",3) == 0) {
729 lastvalid = 1;
730 if (LMAPI->strcasestr(inputbuf, enforceto)) gotaddress = 1;
731 }
732 else if (strncasecmp(inputbuf,"Cc:",3) == 0) {
733 lastvalid = 1;
734 if (LMAPI->strcasestr(inputbuf, enforceto)) gotaddress = 1;
735 }
736 }
737
738 LMAPI->close_file(queuefile);
739
740 if (gotaddress) return HOOK_RESULT_OK;
741
742 if (LMAPI->get_var("enforced-address-blackhole"))
743 return HOOK_RESULT_STOP;
744
745 LMAPI->make_moderated_post("The list address was not in the To or Cc fields. This list does not\naccept Bcc'd posts.");
746
747 return HOOK_RESULT_STOP;
748 }
749
750