]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - subscriptions.c
8fb2a38c6bbcc7db1f4faec4627342a040c2fa5f
[1ts-debian.git] / subscriptions.c
1 /* This file is part of the Project Athena Zephyr Notification System.
2  * It is one of the source files comprising zwgc, the Zephyr WindowGram
3  * client.
4  *
5  *      Created by:     Marc Horowitz <marc@athena.mit.edu>
6  *
7  *      $Id: subscriptions.c 2592 2010-08-24 07:08:36Z kcr@ATHENA.MIT.EDU $
8  *
9  *      Copyright (c) 1989 by the Massachusetts Institute of Technology.
10  *      For copying and distribution information, see the file
11  *      "mit-copyright.h".
12  */
13
14 #if (!defined(lint) && !defined(SABER))
15 static const char rcsid_subscriptions_c[] = "$Id: subscriptions.c 2592 2010-08-24 07:08:36Z kcr@ATHENA.MIT.EDU $";
16 #endif
17
18 /****************************************************************************/
19 /*                                                                          */
20 /*        Subscriptions.c: code to deal with subscriptions & punting:       */
21 /*                                                                          */
22 /****************************************************************************/
23
24 #include <sysdep.h>
25 #include <zephyr/zephyr.h>
26 #include <netdb.h>
27 #include <arpa/nameser.h>
28 #include "new_memory.h"
29 #include "new_string.h"
30 #include "int_dictionary.h"
31 #include "zwgc.h"
32 #include "subscriptions.h"
33 #include "error.h"
34 #include "file.h"
35 #include "main.h"
36
37 /****************************************************************************/
38 /*                                                                          */
39 /*                  Code to implement punting of notices:                   */
40 /*                                                                          */
41 /****************************************************************************/
42
43 /*
44  *
45  */
46 #ifndef CMU_ZCTL_PUNT
47 static
48 #endif
49 int_dictionary puntable_addresses_dict = 0;
50
51 static void
52 init_puntable_dict(void)
53 {
54     puntable_addresses_dict = int_dictionary_Create(33);
55 }
56
57 static string
58 address_to_string(string class,
59                   string instance,
60                   string recipient)
61 {
62     string result;
63
64     /*
65      * Treat a recipient of "" as "*":
66      */
67     if (string_Eq(recipient,""))
68       recipient = "*";
69     else if (recipient[0] == '@') {
70       recipient = string_Concat("*", recipient);
71     }
72
73     /*
74      * The following is a hack for now only.  It should be replaced with
75      * several calls to escape_code... <<<>>>
76      */
77     result = string_Concat(class, "\001");
78     result = string_Concat2(result, instance);
79     result = string_Concat2(result, "\001");
80     result = string_Concat2(result, recipient);
81     string_Downcase(result);
82
83     return(result);
84 }
85
86 int puntable_address_p(string class,
87                        string instance,
88                        string recipient)
89 {
90     string temp;
91     int ret;
92
93     if (!puntable_addresses_dict)
94       init_puntable_dict();
95
96     temp = address_to_string(class, instance, recipient);
97     ret = (int)int_dictionary_Lookup(puntable_addresses_dict, temp);
98     free(temp);
99     if (ret)
100         return 1;;
101
102     /* This kludge is to allow punts of wildcard instance to work */
103     temp = address_to_string(class, "*", recipient);
104     if (int_dictionary_Lookup(puntable_addresses_dict, temp)) {
105         free(temp);
106         return(1);
107     }
108
109     free(temp);
110     return(0);
111 }
112
113 void punt(string class,
114           string instance,
115           string recipient)
116 {
117     string temp;
118
119     if (!puntable_addresses_dict)
120       init_puntable_dict();
121
122     temp = address_to_string(class, instance, recipient);
123     (void)int_dictionary_Define(puntable_addresses_dict, temp, 0);
124     free(temp);
125 }
126
127 void unpunt(string class,
128             string instance,
129             string recipient)
130 {
131     string temp;
132     int_dictionary_binding *binding;
133
134     if (!puntable_addresses_dict)
135       init_puntable_dict();
136
137     temp = address_to_string(class, instance, recipient);
138     binding = int_dictionary_Define(puntable_addresses_dict, temp, 0);
139     free(temp);
140     if (binding)
141       int_dictionary_Delete(puntable_addresses_dict, binding);
142 }
143
144 /****************************************************************************/
145 /*                                                                          */
146 /*           Code to implement batching [un]subscription requests:          */
147 /*                                                                          */
148 /****************************************************************************/
149
150 /*
151  * <<<>>> these routines require zwgc_active to be false (0)
152  */
153
154 #define  BATCH_SIZE   20
155
156 static int subscription_list_size = 0;
157 static ZSubscription_t subscription_list[BATCH_SIZE];
158
159 static int unsubscription_list_size = 0;
160 static ZSubscription_t unsubscription_list[BATCH_SIZE];
161
162 static void
163 free_subscription_list(ZSubscription_t *list,
164                        int number_of_elements)
165 {
166     int i;
167
168     for (i=0; i<number_of_elements; i++) {
169         free(list[i].zsub_class);
170         free(list[i].zsub_classinst);
171         free(list[i].zsub_recipient);
172     }
173 }
174
175 static void
176 flush_subscriptions(void)
177 {
178       TRAP(ZSubscribeTo(subscription_list,subscription_list_size, 0),
179            "while subscribing");
180
181     free_subscription_list(subscription_list, subscription_list_size);
182     subscription_list_size = 0;
183 }
184
185 static void
186 flush_unsubscriptions(void)
187 {
188     if (unsubscription_list_size)
189       TRAP(ZUnsubscribeTo(unsubscription_list, unsubscription_list_size, 0),
190            "while unsubscribing");
191
192     free_subscription_list(unsubscription_list, unsubscription_list_size);
193     unsubscription_list_size = 0;
194 }
195
196 static void
197 subscribe(string class,
198           string instance,
199           string recipient)
200 {
201     subscription_list[subscription_list_size].zsub_class = string_Copy(class);
202     subscription_list[subscription_list_size].zsub_classinst= string_Copy(instance);
203     subscription_list[subscription_list_size].zsub_recipient=string_Copy(recipient);
204
205     if (++subscription_list_size == BATCH_SIZE)
206       flush_subscriptions();
207 }
208
209 static void
210 unsubscribe(string class,
211             string instance,
212             string recipient)
213 {
214     unsubscription_list[unsubscription_list_size].zsub_class = string_Copy(class);
215     unsubscription_list[unsubscription_list_size].zsub_classinst
216       = string_Copy(instance);
217     unsubscription_list[unsubscription_list_size].zsub_recipient
218       = string_Copy(recipient);
219
220     if (++unsubscription_list_size == BATCH_SIZE)
221       flush_unsubscriptions();
222 }
223
224 /****************************************************************************/
225 /*                                                                          */
226 /*         Code to implement reading [un]subscriptions from a file:         */
227 /*                                                                          */
228 /****************************************************************************/
229
230 #define TOKEN_HOSTNAME  "%host%"
231 #define TOKEN_CANONNAME "%canon%"
232 #define TOKEN_ME        "%me%"
233 #define TOKEN_WILD      "*"
234
235 char ourhost[NS_MAXDNAME], ourhostcanon[NS_MAXDNAME];
236
237 static void
238 inithosts(void)
239 {
240     struct hostent *hent;
241     if (gethostname(ourhost, sizeof(ourhost)-1) == -1) {
242         ERROR3("unable to retrieve hostname, %s and %s will be wrong in subscriptions.\n", TOKEN_HOSTNAME, TOKEN_CANONNAME);
243         return;
244     }
245
246     if (!(hent = gethostbyname(ourhost))) {
247         ERROR2("unable to resolve hostname, %s will be wrong in subscriptions.\n", TOKEN_CANONNAME);
248         strncpy(ourhostcanon, ourhost, sizeof(ourhostcanon)-1);
249         return;
250     }
251     strncpy(ourhostcanon, hent->h_name, sizeof(ourhostcanon)-1);
252     return;
253 }
254
255 static void
256 macro_sub(char *str)
257 {
258     static int initedhosts = 0;
259
260     if (!initedhosts) {
261         inithosts();
262         initedhosts = 1;
263     }
264     if (string_Eq(str, TOKEN_ME))
265         strcpy(str, ZGetSender());
266     else if (string_Eq(str, TOKEN_HOSTNAME))
267         strcpy(str, ourhost);
268     else if (string_Eq(str, TOKEN_CANONNAME))
269         strcpy(str, ourhostcanon);
270 }
271
272 #define  UNSUBSCRIBE_CHARACTER  '!'
273 #define  PUNT_CHARACTER         '-'
274
275 static void
276 load_subscriptions_from_file(FILE *file)
277 {
278     char line[BUFSIZ];
279     char class_buffer[BUFSIZ], instance[BUFSIZ], recipient[BUFSIZ];
280     char *class, *temp;
281     char c;
282
283     while ((!feof(file)) && (!ferror(file))) {
284         if (fgets(line, BUFSIZ, file)) {
285             class = class_buffer;
286             /* Parse line */
287             /* <<<>>>
288              * The below does NOT work is the recipient field  is "":
289              */
290             temp = strchr(line, '#');
291             if (temp)
292               *temp = '\0';
293             for (temp=line; *temp && *temp==' '; temp++) ;
294             if (!*temp || *temp=='\n')
295               continue;
296
297             sscanf(temp,"%[^,],%[^,],%s", class, instance, recipient);
298
299             /* skip type indicator if any: */
300             c = class[0];
301             if (c==UNSUBSCRIBE_CHARACTER || c==PUNT_CHARACTER)
302               class++;
303
304             /* perform macro substitutions */
305             macro_sub(class);
306             macro_sub(instance);
307             macro_sub(recipient);
308
309             /* do the right thing with it */
310             switch (c) {
311               case UNSUBSCRIBE_CHARACTER:
312                 unsubscribe(class, instance, recipient);
313                 break;
314               case PUNT_CHARACTER:
315                 punt(class, instance, recipient);
316                 break;
317               default:
318                 subscribe(class, instance, recipient);
319                 break;
320             }
321         } else {
322             break;
323         }
324     }
325
326     if (ferror(file)) {
327         com_err("zwgc", errno, "while reading from subscription file");
328         exit(1);
329     }
330
331     flush_subscriptions();
332     flush_unsubscriptions();
333
334     fclose(file);
335 }
336
337 #define DEFSUBS "/dev/null"
338
339 static void
340 load_subscriptions(void)
341 {
342     FILE *subscriptions_file;
343
344     /* no system default sub file on client--they live on the server */
345     /* BUT...we need to use something to call load_subscriptions_from_file,
346        so we use /dev/null */
347     subscriptions_file = locate_file(subscriptions_filename_override,
348                                      USRSUBS, DEFSUBS);
349     if (subscriptions_file)
350       load_subscriptions_from_file(subscriptions_file);
351 }
352
353 /****************************************************************************/
354 /*                                                                          */
355 /*                Code to implement shutdown and startup:                   */
356 /*                                                                          */
357 /****************************************************************************/
358
359 int zwgc_active = 0;
360
361 static ZSubscription_t *saved_subscriptions = NULL;
362 static int number_of_saved_subscriptions;
363
364 void zwgc_shutdown(void)
365 {
366     if (!zwgc_active)
367       return;
368
369     TRAP(ZRetrieveSubscriptions(0, &number_of_saved_subscriptions),
370          "while retrieving zephyr subscription list");
371     if (error_code)
372       return;
373     saved_subscriptions = (ZSubscription_t *)
374       malloc(number_of_saved_subscriptions*sizeof(ZSubscription_t));
375     if (number_of_saved_subscriptions)
376       TRAP(ZGetSubscriptions(saved_subscriptions,
377                              &number_of_saved_subscriptions),
378            "while getting subscriptions");
379     if (error_code) {
380         free(saved_subscriptions);
381         saved_subscriptions = NULL;
382     }
383     TRAP(ZCancelSubscriptions(0), "while canceling subscriptions") ;
384
385     zwgc_active = 0;
386 }
387
388 void zwgc_startup(void)
389 {
390     if (zwgc_active)
391       return;
392
393     if (saved_subscriptions) {
394         TRAP(ZSubscribeToSansDefaults(saved_subscriptions,number_of_saved_subscriptions,0),
395              "while resubscribing to zephyr messages");
396         free(saved_subscriptions);
397         saved_subscriptions = NULL;
398     } else
399       load_subscriptions();
400
401     zwgc_active = 1;
402 }