1 #include <stdlib.h>
2 #include <string.h>
3 #include <stdio.h>
4 #include "tolist.h"
5 #include "fileapi.h"
6 #include "variables.h"
7 #include "user.h"
8 #include "core.h"
9 #include "smtp.h"
10 #include "forms.h"
11 #include "hooks.h"
12 #include "list.h"
13 #include "mystring.h"
14
15 #ifndef WIN32
16 #include <unistd.h>
17 #endif
18
19 /* These are only used in 'normal' (non megalist) mode */
20 static int elements;
21 struct tolist *sendtolist;
22
23 /* These are used in 'megalist' mode */
24 struct tolist_flag *tolist_flags;
25 char *thelist;
26 FILE *listfile;
27
28 /* These are used in lots of places */
29 struct tolist *current;
30
new_tolist(void)31 void new_tolist(void)
32 {
33 sendtolist = NULL;
34 elements = 0;
35 tolist_flags = NULL;
36 thelist = NULL;
37 }
38
nuke_tolist(void)39 void nuke_tolist(void)
40 {
41 struct tolist *tmp;
42 struct listinfo *l1, *l2;
43 struct tolist_flag *t2;
44 while(sendtolist) {
45 tmp = sendtolist->next;
46 l1 = sendtolist->linfo;
47 while(l1) {
48 l2 = l1->next;
49 if(l1->listname) free(l1->listname);
50 if(l1->listflags) free(l1->listflags);
51 free(l1);
52 l1 = l2;
53 }
54 if(sendtolist->address) free(sendtolist->address);
55 free(sendtolist);
56 sendtolist = tmp;
57 }
58 sendtolist = NULL;
59 elements = 0;
60 while(tolist_flags) {
61 t2 = tolist_flags->next;
62 if(tolist_flags->flag) free(tolist_flags->flag);
63 free(tolist_flags);
64 tolist_flags = t2;
65 }
66 tolist_flags = NULL;
67 if(thelist) free(thelist);
68 thelist = NULL;
69 }
70
find_user(const char * address)71 static struct tolist *find_user(const char *address)
72 {
73 struct tolist *cur = sendtolist;
74 while(cur) {
75 if(strcasecmp(cur->address, address) == 0)
76 return cur;
77 cur = cur->next;
78 }
79 return NULL;
80 }
81
add_from_list_all(const char * list)82 void add_from_list_all(const char *list)
83 {
84 FILE *fp;
85 char buffer[BIG_BUF];
86 struct tolist *user;
87 struct listinfo *l;
88 struct list_user luser;
89 char *listdir;
90
91 if(get_bool("megalist")) {
92 thelist = strdup(list);
93 return;
94 }
95
96 listdir = list_directory(list);
97
98 buffer_printf(buffer, sizeof(buffer) - 1, "%s/users", listdir);
99
100 free(listdir);
101
102 fp = open_file(buffer, "r");
103 if(!fp)
104 return;
105
106 while(user_read(fp, &luser)) {
107 l = (struct listinfo *)malloc(sizeof(struct listinfo));
108 l->listname = strdup(list);
109 l->listflags = strdup(luser.flags);
110 user = find_user(luser.address);
111 if(user) {
112 l->next = user->linfo;
113 } else {
114 user = (struct tolist *)malloc(sizeof(struct tolist));
115 user->next = sendtolist;
116 user->address = strdup(luser.address);
117 sendtolist = user;
118 elements++;
119 l->next = NULL;
120 }
121 user->linfo = l;
122 }
123
124 close_file(fp);
125 }
126
add_from_list_flagged(const char * list,const char * flag)127 void add_from_list_flagged(const char *list, const char *flag)
128 {
129 FILE *fp;
130 char buffer[BIG_BUF];
131 char tbuf[SMALL_BUF];
132 struct tolist *user;
133 struct listinfo *l;
134 struct list_user luser;
135 char *listdir;
136
137 if(get_bool("megalist")) {
138 struct tolist_flag *tmp;
139 if(thelist && strcmp(thelist, list) != 0)
140 return;
141 if(!thelist)
142 thelist = strdup(list);
143 tmp = (struct tolist_flag *)malloc(sizeof(struct tolist_flag));
144 tmp->flag = strdup(flag);
145 tmp->add = 1;
146 tmp->flagged = 1;
147 tmp->next = tolist_flags;
148 tolist_flags = tmp;
149 return;
150 }
151
152 buffer_printf(tbuf, sizeof(tbuf) - 1, "|%s|", flag);
153
154 listdir = list_directory(list);
155
156 buffer_printf(buffer, sizeof(buffer) - 1, "%s/users", listdir);
157
158 free(listdir);
159
160 fp = open_file(buffer, "r");
161 if(!fp)
162 return;
163
164 while(user_read(fp, &luser)) {
165 if(strstr(luser.flags, tbuf) == NULL)
166 continue;
167 l = (struct listinfo *)malloc(sizeof(struct listinfo));
168 l->listname = strdup(list);
169 l->listflags = strdup(luser.flags);
170 user = find_user(luser.address);
171 if(user) {
172 l->next = user->linfo;
173 } else {
174 user = (struct tolist *)malloc(sizeof(struct tolist));
175 user->next = sendtolist;
176 user->address = strdup(luser.address);
177 sendtolist = user;
178 elements++;
179 l->next = NULL;
180 }
181 user->linfo = l;
182 }
183
184 close_file(fp);
185 }
186
add_from_list_unflagged(const char * list,const char * flag)187 void add_from_list_unflagged(const char *list, const char *flag)
188 {
189 FILE *fp;
190 char buffer[BIG_BUF];
191 char tbuf[SMALL_BUF];
192 struct tolist *user;
193 struct listinfo *l;
194 struct list_user luser;
195 char *listdir;
196
197 if(get_bool("megalist")) {
198 struct tolist_flag *tmp;
199 if(thelist && strcmp(thelist, list) != 0)
200 return;
201 if(!thelist)
202 thelist = strdup(list);
203 tmp = (struct tolist_flag *)malloc(sizeof(struct tolist_flag));
204 tmp->flag = strdup(flag);
205 tmp->add = 1;
206 tmp->flagged = 0;
207 tmp->next = tolist_flags;
208 tolist_flags = tmp;
209 return;
210 }
211
212 buffer_printf(tbuf, sizeof(tbuf) - 1, "|%s|", flag);
213
214 listdir = list_directory(list);
215
216 buffer_printf(buffer, sizeof(buffer) - 1, "%s/users", listdir);
217
218 free(listdir);
219
220 fp = open_file(buffer, "r");
221 if(!fp)
222 return;
223
224 while(user_read(fp, &luser)) {
225 if(strstr(luser.flags, tbuf) != NULL)
226 continue;
227 l = (struct listinfo *)malloc(sizeof(struct listinfo));
228 l->listname = strdup(list);
229 l->listflags = strdup(luser.flags);
230 user = find_user(luser.address);
231 if(user) {
232 l->next = user->linfo;
233 } else {
234 user = (struct tolist *)malloc(sizeof(struct tolist));
235 user->next = sendtolist;
236 user->address = strdup(luser.address);
237 sendtolist = user;
238 elements++;
239 l->next = NULL;
240 }
241 user->linfo = l;
242 }
243
244 close_file(fp);
245 }
246
remove_user_all(const char * address)247 void remove_user_all(const char *address)
248 {
249 struct tolist *prev = NULL;
250 struct tolist *cur = sendtolist;
251 struct listinfo *l1, *l2;
252
253 while(cur) {
254 if(strcasecmp(cur->address, address) == 0)
255 break;
256 prev = cur;
257 cur = cur->next;
258 }
259
260 if(!cur)
261 return;
262
263 if(prev) {
264 prev->next = cur->next;
265 } else {
266 sendtolist = cur->next;
267 }
268 elements--;
269
270 l1 = cur->linfo;
271 while(l1) {
272 l2 = l1->next;
273 if(l1->listname) free(l1->listname);
274 if(l1->listflags) free(l1->listflags);
275 free(l1);
276 l1 = l2;
277 }
278 if(cur->address) free(cur->address);
279 free(cur);
280 }
281
282
user_is_flagged(struct tolist * user,const char * flag)283 static int user_is_flagged(struct tolist *user, const char *flag)
284 {
285 char tbuf[SMALL_BUF];
286 struct listinfo *l = user->linfo;
287
288 buffer_printf(tbuf, sizeof(tbuf) - 1, "|%s|", flag);
289 while(l) {
290 if(strstr(l->listflags, tbuf) != NULL)
291 return 1;
292 l = l->next;
293 }
294 return 0;
295 }
296
user_is_flagged_prilist(struct tolist * user,const char * flag,const char * list)297 static int user_is_flagged_prilist(struct tolist *user, const char *flag,
298 const char *list)
299 {
300 char tbuf[SMALL_BUF];
301 struct listinfo *l = user->linfo;
302 int foundit = 0;
303
304 buffer_printf(tbuf, sizeof(tbuf) - 1, "|%s|", flag);
305 while(l) {
306 if(strcasecmp(l->listname, list) == 0) {
307 if(strstr(l->listflags, tbuf) != NULL)
308 return 1;
309 else
310 return 0;
311 } else {
312 if(strstr(l->listflags, tbuf) != NULL)
313 foundit = 1;
314 }
315 l = l->next;
316 }
317 return foundit;
318 }
319
remove_flagged_all_prilist(const char * flag,const char * prilist)320 void remove_flagged_all_prilist(const char *flag, const char *prilist)
321 {
322 struct tolist *cur, *prev, *next;
323 struct listinfo *l1, *l2;
324
325 if(get_bool("megalist")) {
326 struct tolist_flag *tmp;
327 if(thelist && strcmp(thelist, prilist) != 0)
328 return;
329 if(!thelist)
330 thelist = strdup(prilist);
331 tmp = (struct tolist_flag *)malloc(sizeof(struct tolist_flag));
332 tmp->flag = strdup(flag);
333 tmp->add = 0;
334 tmp->flagged = 1;
335 tmp->next = tolist_flags;
336 tolist_flags = tmp;
337 return;
338 }
339
340 cur = sendtolist;
341 prev = NULL;
342 while(cur) {
343 next = cur->next;
344
345 if(user_is_flagged_prilist(cur, flag, prilist)) {
346 elements--;
347 if(prev) {
348 prev->next = next;
349 } else {
350 sendtolist = next;
351 }
352 l1 = cur->linfo;
353 while(l1) {
354 l2 = l1->next;
355 if(l1->listname) free(l1->listname);
356 if(l1->listflags) free(l1->listflags);
357 free(l1);
358 l1 = l2;
359 }
360 if(cur->address) free(cur->address);
361 free(cur);
362 } else {
363 prev = cur;
364 }
365 cur = next;
366 }
367 }
368
remove_flagged_all(const char * flag)369 void remove_flagged_all(const char *flag)
370 {
371 struct tolist *cur, *prev, *next;
372 struct listinfo *l1, *l2;
373
374 if(get_bool("megalist")) {
375 struct tolist_flag *tmp;
376 tmp = (struct tolist_flag *)malloc(sizeof(struct tolist_flag));
377 tmp->flag = strdup(flag);
378 tmp->add = 0;
379 tmp->flagged = 1;
380 tmp->next = tolist_flags;
381 tolist_flags = tmp;
382 return;
383 }
384
385 cur = sendtolist;
386 prev = NULL;
387 while(cur) {
388 next = cur->next;
389
390 if(user_is_flagged(cur, flag)) {
391 elements--;
392 if(prev) {
393 prev->next = next;
394 } else {
395 sendtolist = next;
396 }
397 l1 = cur->linfo;
398 while(l1) {
399 l2 = l1->next;
400 if(l1->listname) free(l1->listname);
401 if(l1->listflags) free(l1->listflags);
402 free(l1);
403 l1 = l2;
404 }
405 if(cur->address) free(cur->address);
406 free(cur);
407 } else {
408 prev = cur;
409 }
410 cur = next;
411 }
412 }
413
remove_unflagged_all(const char * flag)414 void remove_unflagged_all(const char *flag)
415 {
416 struct tolist *cur, *prev, *next;
417 struct listinfo *l1, *l2;
418
419 if(get_bool("megalist")) {
420 struct tolist_flag *tmp;
421 tmp = (struct tolist_flag *)malloc(sizeof(struct tolist_flag));
422 tmp->flag = strdup(flag);
423 tmp->add = 0;
424 tmp->flagged = 0;
425 tmp->next = tolist_flags;
426 tolist_flags = tmp;
427 return;
428 }
429
430 cur = sendtolist;
431 prev = NULL;
432 while(cur) {
433 next = cur->next;
434
435 if(!user_is_flagged(cur, flag)) {
436 elements--;
437 if(prev) {
438 prev->next = next;
439 } else {
440 sendtolist = next;
441 }
442 l1 = cur->linfo;
443 while(l1) {
444 l2 = l1->next;
445 if(l1->listname) free(l1->listname);
446 if(l1->listflags) free(l1->listflags);
447 free(l1);
448 l1 = l2;
449 }
450 if(cur->address) free(cur->address);
451 free(cur);
452 } else {
453 prev = cur;
454 }
455 cur = next;
456 }
457 }
458
remove_unflagged_all_prilist(const char * flag,const char * prilist)459 void remove_unflagged_all_prilist(const char *flag, const char *prilist)
460 {
461 struct tolist *cur, *prev, *next;
462 struct listinfo *l1, *l2;
463
464 if(get_bool("megalist")) {
465 struct tolist_flag *tmp;
466 if(thelist && strcmp(thelist, prilist) != 0)
467 return;
468 if(!thelist)
469 thelist = strdup(prilist);
470 tmp = (struct tolist_flag *)malloc(sizeof(struct tolist_flag));
471 tmp->flag = strdup(flag);
472 tmp->add = 0;
473 tmp->flagged = 0;
474 tmp->next = tolist_flags;
475 tolist_flags = tmp;
476 return;
477 }
478
479 cur = sendtolist;
480 prev = NULL;
481 while(cur) {
482 next = cur->next;
483
484 if(!user_is_flagged_prilist(cur, flag, prilist)) {
485 elements--;
486 if(prev) {
487 prev->next = next;
488 } else {
489 sendtolist = next;
490 }
491 l1 = cur->linfo;
492 while(l1) {
493 l2 = l1->next;
494 if(l1->listname) free(l1->listname);
495 if(l1->listflags) free(l1->listflags);
496 free(l1);
497 l1 = l2;
498 }
499 if(cur->address) free(cur->address);
500 free(cur);
501 } else {
502 prev = cur;
503 }
504 cur = next;
505 }
506 }
507
remove_list_flagged(const char * list,const char * flag)508 void remove_list_flagged(const char *list, const char *flag)
509 {
510 struct tolist *cur, *prev, *next;
511 struct listinfo *curl, *prevl, *nextl;
512 char tbuf[SMALL_BUF];
513 buffer_printf(tbuf, sizeof(tbuf) - 1, "|%s|", flag);
514
515 if(get_bool("megalist")) {
516 struct tolist_flag *tmp;
517 if(thelist && strcmp(thelist, list) != 0)
518 return;
519 if(!thelist)
520 thelist = strdup(list);
521 tmp = (struct tolist_flag *)malloc(sizeof(struct tolist_flag));
522 tmp->flag = strdup(flag);
523 tmp->add = 0;
524 tmp->flagged = 1;
525 tmp->next = tolist_flags;
526 tolist_flags = tmp;
527 return;
528 }
529
530 cur = sendtolist;
531 prev = NULL;
532 while(cur) {
533 next = cur->next;
534
535 /* Remove the list from the user if the list doesn't have the flag */
536 curl = cur->linfo;
537 prevl = NULL;
538 while(curl) {
539 nextl = curl->next;
540 if((strcasecmp(curl->listname, list) == 0) &&
541 (strstr(curl->listflags, tbuf) != NULL)) {
542 if(prevl) {
543 prevl->next = curl->next;
544 } else {
545 cur->linfo = curl->next;
546 }
547 if(curl->listname) free(curl->listname);
548 if(curl->listflags) free(curl->listflags);
549 free(curl);
550 } else {
551 prevl = curl;
552 }
553 curl = nextl;
554 }
555
556 /* If the user is on no more lists, remove him */
557 if(cur->linfo == NULL) {
558 elements--;
559 if(prev) {
560 prev->next = next;
561 } else {
562 sendtolist = next;
563 }
564 if(cur->address) free(cur->address);
565 free(cur);
566 } else {
567 prev = cur;
568 }
569 cur = next;
570 }
571 }
572
remove_list_unflagged(const char * list,const char * flag)573 void remove_list_unflagged(const char *list, const char *flag)
574 {
575 struct tolist *cur, *prev, *next;
576 struct listinfo *curl, *prevl, *nextl;
577 char tbuf[SMALL_BUF];
578 buffer_printf(tbuf, sizeof(tbuf) - 1, "|%s|", flag);
579
580 if(get_bool("megalist")) {
581 struct tolist_flag *tmp;
582 if(thelist && strcmp(thelist, list) != 0)
583 return;
584 if(!thelist)
585 thelist = strdup(list);
586 tmp = (struct tolist_flag *)malloc(sizeof(struct tolist_flag));
587 tmp->flag = strdup(flag);
588 tmp->add = 0;
589 tmp->flagged = 0;
590 tmp->next = tolist_flags;
591 tolist_flags = tmp;
592 return;
593 }
594
595 cur = sendtolist;
596 prev = NULL;
597 while(cur) {
598 next = cur->next;
599
600 /* Remove the list from the user if the list doesn't have the flag */
601 curl = cur->linfo;
602 prevl = NULL;
603 while(curl) {
604 nextl = curl->next;
605 if((strcasecmp(curl->listname, list) == 0) &&
606 (strstr(curl->listflags, tbuf) == NULL)) {
607 if(prevl) {
608 prevl->next = curl->next;
609 } else {
610 cur->linfo = curl->next;
611 }
612 if(curl->listname) free(curl->listname);
613 if(curl->listflags) free(curl->listflags);
614 free(curl);
615 } else {
616 prevl = curl;
617 }
618 curl = nextl;
619 }
620
621 /* If the user is on no more lists, remove him */
622 if(cur->linfo == NULL) {
623 elements--;
624 if(prev) {
625 prev->next = next;
626 } else {
627 sendtolist = next;
628 }
629 if(cur->address) free(cur->address);
630 free(cur);
631 } else {
632 prev = cur;
633 }
634 cur = next;
635 }
636 }
637
tolist_cmp(const void * e1,const void * e2)638 static int tolist_cmp(const void *e1, const void *e2)
639 {
640 struct tolist *t1, *t2;
641 int admin1, admin2;
642 int result, done;
643 char *tptr1, *tptr2;
644 char *cptr1, *cptr2;
645 char *cbuf1, *cbuf2;
646 char *tcptr1, *tcptr2;
647 int comparedat;
648 int countback;
649
650 t1 = *(struct tolist **)e1;
651 t2 = *(struct tolist **)e2;
652
653 admin1 = user_is_flagged(t1, "ADMIN");
654 admin2 = user_is_flagged(t2, "ADMIN");
655
656 if (admin1 != admin2) {
657 if (admin1) return -1;
658 if (admin2) return 1;
659 }
660
661 cbuf1 = strdup(t1->address);
662 cbuf2 = strdup(t2->address);
663
664 cptr1 = strrchr(cbuf1,'.');
665 cptr2 = strrchr(cbuf2,'.');
666
667 tptr1 = strchr(cbuf1,'@');
668 tptr2 = strchr(cbuf2,'@');
669
670 /* If either address has no dots, we'll just do a raw compare. */
671 if (!cptr1 || !cptr2) {
672 return strcasecmp(t1->address,t2->address);
673 }
674
675 /* Quick hack for local addresses with no hostname */
676 /* We technically don't allow these, but better to handle them
677 than to choke and die */
678 if (!tptr1 && !tptr2)
679 {
680 free(cbuf1);
681 free(cbuf2);
682
683 return strcasecmp(t1->address,t2->address);
684 }
685 if (!tptr1)
686 {
687 free(cbuf1);
688 free(cbuf2);
689
690 return -1;
691 }
692 if (!tptr2)
693 {
694 free(cbuf1);
695 free(cbuf2);
696
697 return 1;
698 }
699
700 if (!strcasecmp(tptr1,tptr2)) {
701 /* Same host, just sort on user */
702 free(cbuf1);
703 free(cbuf2);
704 return (strcasecmp(t1->address,t2->address));
705 }
706
707 done = 0; comparedat = 0;
708 countback = 1;
709 result = 0;
710
711 cptr1 = cbuf1 + strlen(cbuf1);
712 cptr2 = cbuf2 + strlen(cbuf2);
713
714 while(done ? 0 : !strcasecmp(cptr1,cptr2)) {
715 char tchar1, tchar2;
716
717 tcptr1 = cptr1; tcptr2 = cptr2;
718
719 tchar1 = *cptr1;
720 tchar2 = *cptr2;
721
722 *cptr1 = 0;
723 *cptr2 = 0;
724
725 cptr1 = strrchr(cbuf1,'.');
726 cptr2 = strrchr(cbuf2,'.');
727 /*
728 *tcptr1 = tchar1;
729 *tcptr2 = tchar2;
730 */
731 if (!cptr1 || !cptr2)
732 {
733 if (!comparedat)
734 {
735 comparedat = 1;
736
737 if (!cptr1)
738 cptr1 = tptr1 + 1;
739 else
740 cptr1++;
741
742 if (!cptr2)
743 cptr2 = tptr2 + 1;
744 else
745 cptr2++;
746 }
747 else
748 {
749 /* Same host, different users */
750 if (!cptr1 && !cptr2) {
751 done = 1;
752 cptr1 = cbuf1;
753 cptr2 = cbuf2;
754 } else
755 {
756 if (!cptr1)
757 result = -1;
758
759 if (!cptr2)
760 result = 1;
761
762 done = 1;
763 }
764 }
765 }
766 }
767
768 if (!result)
769 result = strcasecmp(cptr1, cptr2);
770
771 free(cbuf1);
772 free(cbuf2);
773
774 return result;
775 }
776
sort_tolist(void)777 void sort_tolist(void)
778 {
779 struct tolist *tmp;
780 struct tolist **arr;
781 int i;
782
783 /*
784 * there are a couple of cases where it's not helpful to do
785 * tolist sorting.
786 * In megalist mode, all the users are being read off the disk, so there
787 * is no tolist to sort.
788 * In per-user-modifications mode or smtp-queue-chunk = 1 then
789 * we are going to be sending each message to the SMTP server in a
790 * single envelope anyway, so the order of the tolist is irrelevant
791 */
792 if(get_bool("megalist") || get_bool("per-user-modifications") ||
793 (get_number("smtp-queue-chunk") == 1))
794 return;
795
796 if (!elements) return;
797
798 arr = (struct tolist **)malloc(sizeof(struct tolist *)*elements);
799 if(!arr) return;
800
801 tmp = sendtolist;
802 i = 0;
803 while(tmp) {
804 arr[i++] = tmp;
805 tmp = tmp->next;
806 }
807
808 qsort(arr, elements, sizeof(struct tolist *), tolist_cmp);
809
810 sendtolist = arr[0];
811 tmp = sendtolist;
812 for(i = 1; i < elements; i++) {
813 tmp->next = arr[i];
814 tmp = arr[i];
815 }
816 tmp->next = NULL;
817
818 free(arr);
819 }
820
rev_tolist_flags(struct tolist_flag * list)821 static void rev_tolist_flags(struct tolist_flag * list)
822 {
823 struct tolist_flag *ptr = list->next;
824 if(ptr) {
825 rev_tolist_flags(ptr);
826 ptr->next = list;
827 } else {
828 tolist_flags = list;
829 }
830 list->next = NULL;
831 }
832
tolist_user_matches_flags(struct list_user * user)833 int tolist_user_matches_flags(struct list_user *user)
834 {
835 struct tolist_flag *tmp = tolist_flags;
836 int result = 1;
837 int has;
838
839 log_printf(15, "entering TOLIST_USER_MATCHES_FLAG, (%s -> %s)\n", user->address, user->flags);
840 while(tmp) {
841 log_printf(15, "Checking %s (add: %d) (has: %d)\n", tmp->flag, tmp->add, tmp->flagged);
842 has = user_hasflag(user, tmp->flag);
843 if((tmp->flagged && has) || (!tmp->flagged && !has)) {
844 if(tmp->add && !result)
845 result = 1;
846 else if (!tmp->add && result)
847 result = 0;
848 }
849 tmp = tmp->next;
850 }
851 log_printf(15, "exiting TOLIST_USER_MATCHES_FLAG (%d)\n", result);
852 return result;
853 }
854
start_tolist()855 struct tolist *start_tolist()
856 {
857 log_printf(15, "entering START_TOLIST\n");
858 if(get_bool("megalist")) {
859 char buf[BIG_BUF];
860 struct list_user touser;
861 char *listdir;
862
863 log_printf(15, "START_TOLIST (megalist)\n");
864 if(tolist_flags)
865 rev_tolist_flags(tolist_flags);
866
867 listdir = list_directory(thelist);
868
869 buffer_printf(buf, sizeof(buf) - 1, "%s/users", listdir);
870
871 free(listdir);
872
873 listfile = open_file(buf, "r");
874 if(listfile == NULL) {
875 return NULL;
876 }
877 log_printf(15, "START_TOLIST (megalist) Opened %s\n", thelist);
878 while(user_read(listfile, &touser)) {
879 if(tolist_user_matches_flags(&touser)) {
880 current = (struct tolist *)malloc(sizeof(struct tolist));
881 current->linfo = (struct listinfo *)malloc(sizeof(struct listinfo));
882 current->next = NULL;
883 current->linfo->next = NULL;
884 current->address = strdup(touser.address);
885 current->linfo->listname = strdup(thelist);
886 current->linfo->listflags = strdup(touser.flags);
887 log_printf(15, "START_TOLIST (megalist) returning %s\n", current->address);
888 return current;
889 }
890 }
891 log_printf(15, "START_TOLIST (megalist) done\n");
892 current = NULL;
893 } else {
894 current = sendtolist;
895 if(current) {
896 log_printf(15, "START_TOLIST (not megalist), returning %s\n", current->address);
897 } else {
898 log_printf(15, "START_TOLIST (not megalist), tolist is empty\n");
899 }
900 }
901 return current;
902 }
903
next_tolist()904 struct tolist *next_tolist()
905 {
906 log_printf(15, "entering NEXT_TOLIST\n");
907 if(get_bool("megalist")) {
908 struct list_user touser;
909
910 log_printf(15, "NEXT_TOLIST (megalist)\n");
911 if(listfile == NULL)
912 return NULL;
913
914 while(user_read(listfile, &touser)) {
915 if(tolist_user_matches_flags(&touser)) {
916 current->next = NULL;
917 current->linfo->next = NULL;
918 if(current->address) free(current->address);
919 if(current->linfo->listflags) free(current->linfo->listflags);
920 current->address = strdup(touser.address);
921 current->linfo->listflags = strdup(touser.flags);
922 log_printf(15, "NEXT_TOLIST (megalist) returning %s\n", current->address);
923 return current;
924 }
925 }
926 log_printf(15, "NEXT_TOLIST (megalist) done\n");
927 current = NULL;
928 } else {
929 current = current->next;
930 if(current)
931 log_printf(15, "NEXT_TOLIST (not megalist), returning %s\n", current->address);
932 else
933 log_printf(15, "NEXT_TOLIST (not megalist) done\n");
934 }
935 return current;
936 }
937
finish_tolist()938 void finish_tolist()
939 {
940 struct listinfo *l1, *l2;
941 log_printf(15, "entering FINISH_TOLIST\n");
942 if(get_bool("megalist")) {
943 if(current) {
944 l1 = current->linfo;
945 while(l1) {
946 l2 = l1->next;
947 if(l1->listname) free(l1->listname);
948 if(l1->listflags) free(l1->listflags);
949 free(l1);
950 l1 = l2;
951 }
952 if(current->address) free(current->address);
953 free(current);
954 }
955 if(listfile)
956 close_file(listfile);
957 }
958 current = NULL;
959 }
960
send_to_tolist(const char * fromaddy,const char * file,int do_ackpost,int do_echopost,int fullbounce)961 int send_to_tolist(const char *fromaddy, const char *file,
962 int do_ackpost, int do_echopost, int fullbounce)
963 {
964 int chunksize = get_number("smtp-queue-chunk");
965 int count;
966 struct tolist *ttolist, *otolist = NULL;
967 int errors = 0;
968 int total_errors = 0;
969 int sentusers = 0;
970 int total_sent = 0;
971 int val = 0;
972 FILE *errfile;
973 FILE *infile = NULL;
974 char buffer[BIG_BUF];
975 char userfilepath[BIG_BUF];
976 struct list_user user;
977 int founduser=0;
978 int peruser = get_bool("per-user-modifications");
979 const char *list = get_var("list");
980
981 if(chunksize == 0) count = -1;
982 else count = chunksize;
983
984 if(peruser && chunksize != 1) {
985 log_printf(1, "Queue chunk != 1, disabling per user queue modificaton.\n");
986 peruser = 0;
987 }
988
989 if(!exists_file(file))
990 return 0;
991
992 if(peruser) {
993 FILE *copyfile = NULL;
994
995 /* Set up our queuefile and variables */
996 buffer_printf(buffer, sizeof(buffer) - 1 , "%s.user", get_string("queuefile"));
997 set_var("per-user-queuefile", buffer, VAR_TEMP);
998 set_var("per-user-datafile", file, VAR_TEMP);
999
1000 if ((infile = open_file(file, "r")) == NULL) {
1001 filesys_error(file);
1002 return 0;
1003 }
1004
1005 if ((copyfile = open_file(buffer, "w")) == NULL) {
1006 close_file(infile);
1007 filesys_error(buffer);
1008 return 0;
1009 }
1010
1011 while(read_file(buffer, sizeof(buffer), infile)) {
1012 write_file(copyfile, "%s", buffer);
1013 }
1014
1015 close_file(infile);
1016 close_file(copyfile);
1017
1018 infile = NULL;
1019 }
1020
1021 if((do_ackpost || do_echopost) && list) {
1022 char *listdir;
1023
1024 listdir = list_directory(list);
1025 buffer_printf(userfilepath, sizeof(userfilepath) - 1, "%s/users", listdir);
1026 free(listdir);
1027 founduser = user_find_list(list, get_string("fromaddress"), &user);
1028 }
1029
1030 if(!founduser) {
1031 strncpy(user.address, "", BIG_BUF - 1);
1032 strncpy(user.flags, "", HUGE_BUF - 1);
1033 }
1034
1035 if(do_ackpost && list) {
1036 if(founduser && user_hasflag(&user, "ACKPOST")) {
1037 char tbuf[SMALL_BUF];
1038 buffer_printf(tbuf, sizeof(tbuf) - 1, "Post received for list '%s'", list);
1039 set_var("task-form-subject",&tbuf[0],VAR_TEMP);
1040 if(task_heading(user.address)) {
1041 if (get_var("message-subject")) {
1042 smtp_body_line("Your post entitled:");
1043 smtp_body_text(" ");
1044 smtp_body_line(get_string("message-subject"));
1045 } else {
1046 smtp_body_text("Your post ");
1047 }
1048 smtp_body_text("was received for list '");
1049 smtp_body_text(get_string("list"));
1050 smtp_body_line("'.");
1051 task_ending();
1052 }
1053 }
1054 }
1055
1056 ttolist = start_tolist();
1057 buffer_printf(buffer, sizeof(buffer) - 1, "%s.serr", get_string("queuefile"));
1058 set_var("smtp-errors-file", buffer, VAR_GLOBAL);
1059 errfile = open_file(buffer, "w");
1060
1061 if(!peruser) {
1062 infile = open_file(file, "r");
1063 if(!infile)
1064 return 0;
1065 }
1066
1067 while(ttolist) {
1068
1069 sentusers = 0;
1070 errors = 0;
1071 if(!smtp_start(fullbounce))
1072 return 0;
1073
1074 if(!smtp_from(fromaddy))
1075 return 0;
1076 while(ttolist && ((count == -1) || (count > 0))) {
1077 if(!do_echopost ||
1078 (user_hasflag(&user, "ECHOPOST") ||
1079 strcasecmp(user.address, ttolist->address))) {
1080 if(!smtp_to(ttolist->address)) {
1081 if(errfile)
1082 write_file(errfile, "%s\n",
1083 get_string("smtp-last-error"));
1084 errors++;
1085 total_errors++;
1086 }
1087 sentusers++;
1088 total_sent++;
1089 if(count != -1) count--;
1090 }
1091 otolist = ttolist;
1092 ttolist = next_tolist();
1093 }
1094
1095 if(peruser) {
1096 int res, done;
1097 char *peruserlist = NULL;
1098 struct listinfo *li = NULL;
1099
1100 if(otolist != NULL) {
1101 set_var("per-user-data", (char *)otolist, VAR_TEMP);
1102 set_var("per-user-address", otolist->address, VAR_TEMP);
1103 li = otolist->linfo;
1104 }
1105
1106 done = 0;
1107
1108 while(li && !done) {
1109 peruserlist = li->listname;
1110 if (list && (strcmp(peruserlist,list) == 0))
1111 done = 1;
1112 li = li->next;
1113 }
1114
1115 set_var("per-user-list", peruserlist, VAR_TEMP);
1116
1117 res = do_hooks("PER-USER");
1118 if(res == HOOK_RESULT_FAIL) {
1119 unlink_file(buffer);
1120 return 0;
1121 } else if(res == HOOK_RESULT_STOP) {
1122 ttolist = ttolist->next;
1123 continue;
1124 }
1125 infile = open_file(get_string("per-user-queuefile"), "r");
1126 if(!infile)
1127 return 0;
1128 }
1129
1130 if(sentusers && (sentusers != errors)) {
1131 int line = 0;
1132 if(!smtp_body_start())
1133 return 0;
1134 while(read_file(buffer, sizeof(buffer), infile)) {
1135 if(line != 0 || strncmp(buffer, "From ", 5) != 0)
1136 smtp_body_text(buffer);
1137 line++;
1138 }
1139 smtp_body_end();
1140 }
1141 smtp_end();
1142
1143 if(count != -1) count = chunksize;
1144 if(peruser) {
1145 FILE *copyfile;
1146
1147 close_file(infile);
1148 unlink_file(get_var("per-user-queuefile"));
1149
1150 if ((infile = open_file(file, "r")) == NULL) {
1151 filesys_error(file);
1152 return 0;
1153 }
1154
1155 if ((copyfile = open_file(get_var("per-user-queuefile"), "w")) == NULL) {
1156 close_file(infile);
1157 filesys_error(get_var("per-user-queuefile"));
1158 return 0;
1159 }
1160
1161 while(read_file(buffer, sizeof(buffer), infile)) {
1162 write_file(copyfile, "%s", buffer);
1163 }
1164
1165 close_file(infile);
1166 close_file(copyfile);
1167
1168 infile = NULL;
1169
1170 } else {
1171 rewind_file(infile);
1172 }
1173
1174 /* Now pause a bit if we are requested to */
1175 val = get_number("tolist-send-pause");
1176 if(ttolist && val) {
1177 do_sleep(val);
1178 }
1179 }
1180
1181 finish_tolist();
1182
1183 clean_var("per-user-queuefile", VAR_TEMP);
1184 clean_var("per-user-datafile", VAR_TEMP);
1185 clean_var("per-user-data", VAR_TEMP);
1186
1187 close_file(infile);
1188
1189 if(total_errors && total_sent && errfile) {
1190 close_file(errfile);
1191 bounce_message();
1192 } else {
1193 if(errfile)
1194 close_file(errfile);
1195 }
1196 buffer_printf(buffer, sizeof(buffer) - 1, "%s.serr", get_string("queuefile"));
1197 unlink_file(buffer);
1198
1199 if(peruser) {
1200 buffer_printf(buffer, sizeof(buffer) - 1, "%s.user", get_string("queuefile"));
1201 unlink_file(buffer);
1202 }
1203
1204 if(total_errors && total_errors == total_sent)
1205 return 0;
1206 return 1;
1207 }
1208
1209