1 /* This file is part of the Project Athena Zephyr Notification System.
2  * It contains source for the ZSubscribeTo, ZUnsubscribeTo, and
3  * ZCancelSubscriptions functions.
4  *
5  *	Created by:	Robert French
6  *
7  *	Copyright (c) 1987,1988 by the Massachusetts Institute of Technology.
8  *	For copying and distribution information, see the file
9  *	"mit-copyright.h".
10  */
11 
12 #include "internal.h"
13 
14 static Code_t Z_Subscriptions __P((register ZSubscription_t *sublist,
15 				   int nitems, unsigned int port,
16 				   char *opcode, int authit));
17 static Code_t subscr_sendoff __P((ZNotice_t *notice, char **lyst, int num,
18 				  int authit));
19 
ZSubscribeTo(sublist,nitems,port)20 Code_t ZSubscribeTo(sublist, nitems, port)
21     ZSubscription_t *sublist;
22     int nitems;
23     unsigned int port;
24 {
25     return (Z_Subscriptions(sublist, nitems, port, CLIENT_SUBSCRIBE, 1));
26 }
27 
ZSubscribeToSansDefaults(sublist,nitems,port)28 Code_t ZSubscribeToSansDefaults(sublist, nitems, port)
29     ZSubscription_t *sublist;
30     int nitems;
31     unsigned int port;
32 {
33     return (Z_Subscriptions(sublist, nitems, port, CLIENT_SUBSCRIBE_NODEFS,
34 			    1));
35 }
36 
ZUnsubscribeTo(sublist,nitems,port)37 Code_t ZUnsubscribeTo(sublist, nitems, port)
38     ZSubscription_t *sublist;
39     int nitems;
40     unsigned int port;
41 {
42     return (Z_Subscriptions(sublist, nitems, port, CLIENT_UNSUBSCRIBE, 1));
43 }
44 
ZCancelSubscriptions(port)45 Code_t ZCancelSubscriptions(port)
46     unsigned int port;
47 {
48     return (Z_Subscriptions((ZSubscription_t *)0, 0, port,
49 			    CLIENT_CANCELSUB, 0));
50 }
51 
52 /*
53  * This routine must do its own fragmentation.  Subscriptions must
54  * not be broken across packet boundaries, or else the server will
55  * mis-interpret them.
56  */
57 
58 static Code_t
Z_Subscriptions(sublist,nitems,port,opcode,authit)59 Z_Subscriptions(sublist, nitems, port, opcode, authit)
60     register ZSubscription_t *sublist;
61     int nitems;
62     unsigned int port;
63     char *opcode;
64     int authit;
65 {
66     register int i, j;
67     int retval;
68     ZNotice_t notice;
69     char header[Z_MAXHEADERLEN];
70     char **list;
71     char *recip;
72     int hdrlen;
73     int size_avail = Z_MAXPKTLEN-Z_FRAGFUDGE; /* space avail for data,
74 						 adjusted below */
75     int size, start, numok;
76 
77     /* nitems = 0 means cancel all subscriptions; still need to allocate a */
78     /* array for one item so we can cancel, however. */
79 
80     list = (char **)malloc((unsigned)((nitems==0)?1:nitems)*3*sizeof(char *));
81     if (!list)
82         return (ENOMEM);
83 
84     (void) memset((char *)&notice, 0, sizeof(notice));
85     notice.z_kind = ACKED;
86     notice.z_port = port;
87     notice.z_class = ZEPHYR_CTL_CLASS;
88     notice.z_class_inst = ZEPHYR_CTL_CLIENT;
89     notice.z_opcode = opcode;
90     notice.z_sender = 0;
91     notice.z_recipient = "";
92     notice.z_default_format = "";
93     notice.z_message_len = 0;
94 
95     /* format the header to figure out how long it is */
96     retval = Z_FormatHeader(&notice, header, sizeof(header), &hdrlen, ZAUTH);
97     if (retval != ZERR_NONE && !authit)
98 	retval = Z_FormatHeader(&notice, header, sizeof(header),
99 				&hdrlen, ZNOAUTH);
100     if (retval != ZERR_NONE) {
101 	free((char *)list);
102 	return(retval);
103     }
104 
105     /* compute amount of room left */
106     size_avail -= hdrlen;
107     size = size_avail;
108 
109     /* assemble subs into an array of pointers */
110     for (i=0;i<nitems;i++) {
111 	list[i*3] = sublist[i].zsub_class;
112 	list[i*3+1] = sublist[i].zsub_classinst;
113 	recip = sublist[i].zsub_recipient;
114 	if (recip && *recip == '*')
115 	  recip++;
116 	if (!recip || (*recip != 0 && *recip != '@'))
117 	  recip = ZGetSender();
118 	list[i*3+2] = recip;
119     }
120 
121     start = -1;
122     i = 0;
123     numok = 0;
124     if (!nitems) {
125 	/* there aren't really any, but we need to xmit anyway */
126 	retval = subscr_sendoff(&notice, list, 0, authit);
127 	free((char *)list);
128 	return(retval);
129     }
130     while(i < nitems) {
131 	if (start == -1) {
132 	    size = size_avail;
133 	    start = i;
134 	    numok = 0;
135 	}
136 	if ((j = strlen(list[i*3])
137 	     + strlen(list[i*3+1])
138 	     + strlen(list[i*3+2]) + 3) <= size) {
139 	    /* it will fit in this packet */
140 	    size -= j;
141 	    numok++;
142 	    i++;
143 	    continue;
144 	}
145 	if (!numok) {			/* a single subscription won't
146 					   fit into one packet */
147 	    free((char *)list);
148 	    return(ZERR_FIELDLEN);
149 	}
150 	retval = subscr_sendoff(&notice, &list[start*3], numok, authit);
151 	if (retval) {
152 	    free((char *)list);
153 	    return(retval);
154 	}
155 	start = -1;
156     }
157     if (numok)
158 	retval = subscr_sendoff(&notice, &list[start*3], numok, authit);
159     free((char *)list);
160     return(retval);
161 }
162 
163 static Code_t
subscr_sendoff(notice,lyst,num,authit)164 subscr_sendoff(notice, lyst, num, authit)
165 ZNotice_t *notice;
166 char **lyst;
167 int num;
168 int authit;
169 {
170     register Code_t retval;
171     ZNotice_t retnotice;
172 
173     retval = ZSendList(notice, lyst, num*3, ZAUTH);
174     if (retval != ZERR_NONE && !authit)
175 	retval = ZSendList(notice, lyst, num*3, ZNOAUTH);
176 
177     if (retval != ZERR_NONE)
178 	return (retval);
179     if ((retval = ZIfNotice(&retnotice, (struct sockaddr_in *)0,
180 				ZCompareUIDPred, (char *)&notice->z_uid)) !=
181 	ZERR_NONE)
182 	return (retval);
183     if (retnotice.z_kind == SERVNAK) {
184 	ZFreeNotice(&retnotice);
185 	return (ZERR_SERVNAK);
186     }
187     if (retnotice.z_kind != SERVACK) {
188 	ZFreeNotice(&retnotice);
189 	return (ZERR_INTERNAL);
190     }
191     ZFreeNotice(&retnotice);
192     return (ZERR_NONE);
193 }
194