xref: /plan9/sys/src/cmd/upas/send/bind.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include "common.h"
2 #include "send.h"
3 
4 static int forward_loop(char *, char *);
5 
6 /* bind the destinations to the commands to be executed */
7 extern dest *
8 up_bind(dest *destp, message *mp, int checkforward)
9 {
10 	dest *list[2];		/* lists of unbound destinations */
11 	int li;			/* index into list[2] */
12 	dest *bound=0;	/* bound destinations */
13 	dest *dp;
14 	int i;
15 
16 	list[0] = destp;
17 	list[1] = 0;
18 
19 	/*
20 	 *  loop once to check for:
21 	 *	- forwarding rights
22 	 *	- addressing loops
23 	 *	- illegal characters
24 	 */
25 	for (dp = d_rm(&list[0]); dp != 0; dp = d_rm(&list[0])) {
26 		if (!checkforward)
27 			dp->authorized = 1;
28 		if (forward_loop(s_to_c(dp->addr), thissys)) {
29 			dp->status = d_eloop;
30 			d_same_insert(&bound, dp);
31 		} else if(forward_loop(s_to_c(mp->sender), thissys)) {
32 			dp->status = d_eloop;
33 			d_same_insert(&bound, dp);
34 		} else if(shellchars(s_to_c(dp->addr))) {
35 			dp->status = d_syntax;
36 			d_same_insert(&bound, dp);
37 		} else
38 			d_insert(&list[1], dp);
39 	}
40 	li = 1;
41 
42 	/* Loop until all addresses are bound or address loop detected */
43 	for (i=0; list[li]!=0 && i<32; ++i, li ^= 1) {
44 		/* Traverse the current list.  Bound items are put on the
45 		 * `bound' list.  Unbound items are put on the next list to
46 		 * traverse, `list[li^1]'.
47 		 */
48 		for (dp = d_rm(&list[li]); dp != 0; dp = d_rm(&list[li])){
49 			dest *newlist;
50 
51 			rewrite(dp, s_to_c(mp->replyaddr));
52 			if(debug)
53 				fprint(2, "%s -> %s\n", s_to_c(dp->addr),
54 					dp->repl1 ? s_to_c(dp->repl1):"");
55 			switch (dp->status) {
56 			case d_auth:
57 				/* authorize address if not already authorized */
58 				if(!dp->authorized){
59 					authorize(dp);
60 					if(dp->status==d_auth)
61 						d_insert(&list[li^1], dp);
62 					else
63 						d_insert(&bound, dp);
64 				}
65 				break;
66 			case d_cat:
67 				/* address -> local */
68 				newlist = expand_local(dp);
69 				if (newlist == 0) {
70 					/* append to mailbox (or error) */
71 					d_same_insert(&bound, dp);
72 				} else if (newlist->status == d_undefined) {
73 					/* Forward to ... */
74 					d_insert(&list[li^1], newlist);
75 				} else {
76 					/* Pipe to ... */
77 					d_same_insert(&bound, newlist);
78 				}
79 				break;
80 			case d_pipe:
81 				/* address -> command */
82 				d_same_insert(&bound, dp);
83 				break;
84 			case d_alias:
85 				/* address -> rewritten address */
86 				newlist = s_to_dest(dp->repl1, dp);
87 				if(newlist != 0)
88 					d_insert(&list[li^1], newlist);
89 				else
90 					d_same_insert(&bound, dp);
91 				break;
92 			case d_translate:
93 				/* pipe to a translator */
94 				newlist = translate(dp);
95 				if (newlist != 0)
96 					d_insert(&list[li^1], newlist);
97 				else
98 					d_same_insert(&bound, dp);
99 				break;
100 			default:
101 				/* error */
102 				d_same_insert(&bound, dp);
103 				break;
104 			}
105 		}
106 	}
107 
108 	/* mark remaining comands as "forwarding loops" */
109 	for (dp = d_rm(&list[li]); dp != 0; dp = d_rm(&list[li])) {
110 		dp->status = d_loop;
111 		d_same_insert(&bound, dp);
112 	}
113 
114 	return bound;
115 }
116 
117 /* Return TRUE if a forwarding loop exists, i.e., the String `system'
118  * is found more than 4 times in the return address.
119  */
120 static int
121 forward_loop(char *addr, char *system)
122 {
123 	int len = strlen(system), found = 0;
124 
125 	while (addr = strchr(addr, '!'))
126 		if (!strncmp(++addr, system, len)
127 		 && addr[len] == '!' && ++found == 4)
128 			return 1;
129 	return 0;
130 }
131 
132