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