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