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