]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/lib/ZSubs.c
e8519fe69a7a054185498d2db431385768f275a7
[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(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 Code_t
27 ZSubscribeTo(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
35 ZSubscribeToSansDefaults(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
44 ZUnsubscribeTo(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
52 ZCancelSubscriptions(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(register ZSubscription_t *sublist,
66                 int nitems,
67                 unsigned int port,
68                 char *opcode,
69                 int authit)
70 {
71     register int i, j;
72     int retval;
73     ZNotice_t notice;
74     char header[Z_MAXHEADERLEN];
75     char **list;
76     char *recip;
77     int hdrlen;
78     int size_avail = Z_MAXPKTLEN-Z_FRAGFUDGE; /* space avail for data,
79                                                  adjusted below */
80     int size, start, numok;
81
82     /* nitems = 0 means cancel all subscriptions; still need to allocate a */
83     /* array for one item so we can cancel, however. */
84   
85     list = (char **)malloc((unsigned)((nitems==0)?1:nitems)*3*sizeof(char *));
86     if (!list)
87         return (ENOMEM);
88
89     (void) memset((char *)&notice, 0, sizeof(notice));
90     notice.z_kind = ACKED;
91     notice.z_port = port;
92     notice.z_class = ZEPHYR_CTL_CLASS;
93     notice.z_class_inst = ZEPHYR_CTL_CLIENT;
94     notice.z_opcode = opcode;
95     notice.z_sender = 0;
96     notice.z_recipient = "";
97     notice.z_default_format = "";
98     notice.z_message_len = 0;
99
100     /* format the header to figure out how long it is */
101     retval = Z_FormatHeader(&notice, header, sizeof(header), &hdrlen, ZAUTH);
102     if (retval != ZERR_NONE && !authit)
103         retval = Z_FormatHeader(&notice, header, sizeof(header),
104                                 &hdrlen, ZNOAUTH);
105     if (retval != ZERR_NONE) {
106         free((char *)list);
107         return(retval);
108     }
109
110     /* compute amount of room left */
111     size_avail -= hdrlen;
112     size = size_avail;
113
114     /* assemble subs into an array of pointers */
115     for (i=0;i<nitems;i++) {
116         list[i*3] = sublist[i].zsub_class;
117         list[i*3+1] = sublist[i].zsub_classinst;
118         recip = sublist[i].zsub_recipient;
119         if (recip && *recip == '*')
120             recip++;
121         if (!recip || (*recip != 0 && *recip != '@'))
122             recip = ZGetSender();
123         list[i*3+2] = recip;
124     }
125
126     start = -1;
127     i = 0;
128     numok = 0;
129     if (!nitems) {
130         /* there aren't really any, but we need to xmit anyway */
131         retval = subscr_sendoff(&notice, list, 0, authit);
132         free((char *)list);
133         return(retval);
134     }
135     while(i < nitems) {
136         if (start == -1) {
137             size = size_avail;
138             start = i;
139             numok = 0;
140         }
141         if ((j = strlen(list[i*3])
142              + strlen(list[i*3+1])
143              + strlen(list[i*3+2]) + 3) <= size) {
144             /* it will fit in this packet */
145             size -= j;
146             numok++;
147             i++;
148             continue;
149         }
150         if (!numok) {                   /* a single subscription won't
151                                            fit into one packet */
152             free((char *)list);
153             return(ZERR_FIELDLEN);
154         }
155         retval = subscr_sendoff(&notice, &list[start*3], numok, authit);
156         if (retval) {
157             free((char *)list);
158             return(retval);
159         }
160         start = -1;
161     }
162     if (numok)
163         retval = subscr_sendoff(&notice, &list[start*3], numok, authit);
164     free((char *)list);
165     return(retval);
166 }
167
168 static Code_t
169 subscr_sendoff(ZNotice_t *notice,
170                char **lyst,
171                int num,
172                int authit)
173 {
174     register Code_t retval;
175     ZNotice_t retnotice;
176
177     retval = ZSendList(notice, lyst, num*3, ZAUTH);
178     if (retval != ZERR_NONE && !authit)
179         retval = ZSendList(notice, lyst, num*3, ZNOAUTH);
180         
181     if (retval != ZERR_NONE)
182         return (retval);
183     if ((retval = ZIfNotice(&retnotice, (struct sockaddr_in *)0, 
184                                 ZCompareUIDPred, (char *)&notice->z_uid)) !=
185         ZERR_NONE)
186         return (retval);
187     if (retnotice.z_kind == SERVNAK) {
188         ZFreeNotice(&retnotice);
189         return (ZERR_SERVNAK);
190     }
191     if (retnotice.z_kind != SERVACK) {
192         ZFreeNotice(&retnotice);
193         return (ZERR_INTERNAL);
194     }
195     ZFreeNotice(&retnotice);
196     return (ZERR_NONE);
197 }