xref: /plan9/sys/src/cmd/upas/ml/common.c (revision 2715b72ad01e83fb7071c22cc0015e1c17a12770)
1 #include "common.h"
2 #include "dat.h"
3 
4 String*
getaddr(Node * p)5 getaddr(Node *p)
6 {
7 	for(; p; p = p->next){
8 		if(p->s && p->addr)
9 			return p->s;
10 	}
11 	return nil;
12 }
13 
14 /* send message adding our own reply-to and precedence */
15 void
getaddrs(void)16 getaddrs(void)
17 {
18 	Field *f;
19 
20 	for(f = firstfield; f; f = f->next){
21 		if(f->node->c == FROM && from == nil)
22 			from = getaddr(f->node);
23 		if(f->node->c == SENDER && sender == nil)
24 			sender = getaddr(f->node);
25 	}
26 }
27 
28 /* write address file, should be append only */
29 void
writeaddr(char * file,char * addr,int rem,char * listname)30 writeaddr(char *file, char *addr, int rem, char *listname)
31 {
32 	int fd;
33 	Dir nd;
34 
35 	fd = open(file, OWRITE);
36 	if(fd < 0){
37 		fd = create(file, OWRITE, DMAPPEND|0666);
38 		if(fd < 0)
39 			sysfatal("creating address list %s: %r", file);
40 		nulldir(&nd);
41 		nd.mode = DMAPPEND|0666;
42 		dirwstat(file, &nd);
43 	} else
44 		seek(fd, 0, 2);
45 	if(rem)
46 		fprint(fd, "!%s\n", addr);
47 	else
48 		fprint(fd, "%s\n", addr);
49 	close(fd);
50 
51 	if(*addr != '#')
52 		sendnotification(addr, listname, rem);
53 }
54 
55 void
remaddr(char * addr)56 remaddr(char *addr)
57 {
58 	Addr **l;
59 	Addr *a;
60 
61 	for(l = &al; *l; l = &(*l)->next){
62 		a = *l;
63 		if(strcmp(addr, a->addr) == 0){
64 			(*l) = a->next;
65 			free(a);
66 			na--;
67 			break;
68 		}
69 	}
70 }
71 
72 int
addaddr(char * addr)73 addaddr(char *addr)
74 {
75 	Addr **l;
76 	Addr *a;
77 
78 	for(l = &al; *l; l = &(*l)->next){
79 		if(strcmp(addr, (*l)->addr) == 0)
80 			return 0;
81 	}
82 	na++;
83 	*l = a = malloc(sizeof(*a)+strlen(addr)+1);
84 	if(a == nil)
85 		sysfatal("allocating: %r");
86 	a->addr = (char*)&a[1];
87 	strcpy(a->addr, addr);
88 	a->next = nil;
89 	*l = a;
90 	return 1;
91 }
92 
93 /* read address file */
94 void
readaddrs(char * file)95 readaddrs(char *file)
96 {
97 	Biobuf *b;
98 	char *p;
99 
100 	b = Bopen(file, OREAD);
101 	if(b == nil)
102 		return;
103 
104 	while((p = Brdline(b, '\n')) != nil){
105 		p[Blinelen(b)-1] = 0;
106 		if(*p == '#')
107 			continue;
108 		if(*p == '!')
109 			remaddr(p+1);
110 		else
111 			addaddr(p);
112 	}
113 	Bterm(b);
114 }
115 
116 /* start a mailer sending to all the receivers for list `name' */
117 int
startmailer(char * name)118 startmailer(char *name)
119 {
120 	int pfd[2];
121 	char **av;
122 	int ac;
123 	Addr *a;
124 
125 	/*
126 	 * we used to send mail to the list from /dev/null,
127 	 * which is equivalent to an smtp return address of <>,
128 	 * but such a return address should only be used when
129 	 * sending a bounce to a single address.  our smtpd lets
130 	 * such mail through, but refuses mail from <> to multiple
131 	 * addresses, since that's not allowed and is likely spam.
132 	 * thus mailing list mail to another upas system with
133 	 * multiple addressees was being rejected.
134 	 */
135 	putenv("upasname", smprint("%s-owner", name));
136 
137 	if(pipe(pfd) < 0)
138 		sysfatal("creating pipe: %r");
139 	switch(fork()){
140 	case -1:
141 		sysfatal("starting mailer: %r");
142 	case 0:
143 		close(pfd[1]);
144 		break;
145 	default:
146 		close(pfd[0]);
147 		return pfd[1];
148 	}
149 
150 	dup(pfd[0], 0);
151 	close(pfd[0]);
152 
153 	av = malloc(sizeof(char*)*(na+2));
154 	if(av == nil)
155 		sysfatal("starting mailer: %r");
156 	ac = 0;
157 	av[ac++] = name;
158 	for(a = al; a != nil; a = a->next)
159 		av[ac++] = a->addr;
160 	av[ac] = 0;
161 	exec("/bin/upas/send", av);
162 	sysfatal("execing mailer: %r");
163 
164 	/* not reached */
165 	return -1;
166 }
167 
168 void
sendnotification(char * addr,char * listname,int rem)169 sendnotification(char *addr, char *listname, int rem)
170 {
171 	int pfd[2];
172 	Waitmsg *w;
173 
174 	putenv("upasname", smprint("%s-owner", listname));
175 	if(pipe(pfd) < 0)
176 		sysfatal("creating pipe: %r");
177 	switch(fork()){
178 	case -1:
179 		sysfatal("starting mailer: %r");
180 	case 0:
181 		close(pfd[1]);
182 		dup(pfd[0], 0);
183 		close(pfd[0]);
184 		execl("/bin/upas/send", "mlnotify", addr, nil);
185 		sysfatal("execing mailer: %r");
186 		break;
187 	default:
188 		close(pfd[0]);
189 		fprint(pfd[1], "From: %s-owner\n\n", listname);
190 		if(rem)
191 			fprint(pfd[1], "You have been removed from the %s mailing list\n", listname);
192 		else{
193 			fprint(pfd[1], "You have been added to the %s mailing list\n", listname);
194 			fprint(pfd[1], "To be removed, send an email to %s-owner containing\n",
195 				listname);
196 			fprint(pfd[1], "the word 'remove' in the subject or body.\n");
197 		}
198 		close(pfd[1]);
199 
200 		/* wait for mailer to end */
201 		while(w = wait()){
202 			if(w->msg != nil && w->msg[0])
203 				sysfatal("%s", w->msg);
204 			free(w);
205 		}
206 		break;
207 	}
208 }
209