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