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
5 * Created by: Marc Horowitz <marc@athena.mit.edu>
7 * $Id: subscriptions.c 2592 2010-08-24 07:08:36Z kcr@ATHENA.MIT.EDU $
9 * Copyright (c) 1989 by the Massachusetts Institute of Technology.
10 * For copying and distribution information, see the file
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 $";
18 /****************************************************************************/
20 /* Subscriptions.c: code to deal with subscriptions & punting: */
22 /****************************************************************************/
25 #include <zephyr/zephyr.h>
27 #include <arpa/nameser.h>
28 #include "new_memory.h"
29 #include "new_string.h"
30 #include "int_dictionary.h"
32 #include "subscriptions.h"
37 /****************************************************************************/
39 /* Code to implement punting of notices: */
41 /****************************************************************************/
49 int_dictionary puntable_addresses_dict = 0;
52 init_puntable_dict(void)
54 puntable_addresses_dict = int_dictionary_Create(33);
58 address_to_string(string class,
65 * Treat a recipient of "" as "*":
67 if (string_Eq(recipient,""))
69 else if (recipient[0] == '@') {
70 recipient = string_Concat("*", recipient);
74 * The following is a hack for now only. It should be replaced with
75 * several calls to escape_code... <<<>>>
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);
86 int puntable_address_p(string class,
93 if (!puntable_addresses_dict)
96 temp = address_to_string(class, instance, recipient);
97 ret = (int)int_dictionary_Lookup(puntable_addresses_dict, temp);
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)) {
113 void punt(string class,
119 if (!puntable_addresses_dict)
120 init_puntable_dict();
122 temp = address_to_string(class, instance, recipient);
123 (void)int_dictionary_Define(puntable_addresses_dict, temp, 0);
127 void unpunt(string class,
132 int_dictionary_binding *binding;
134 if (!puntable_addresses_dict)
135 init_puntable_dict();
137 temp = address_to_string(class, instance, recipient);
138 binding = int_dictionary_Define(puntable_addresses_dict, temp, 0);
141 int_dictionary_Delete(puntable_addresses_dict, binding);
144 /****************************************************************************/
146 /* Code to implement batching [un]subscription requests: */
148 /****************************************************************************/
151 * <<<>>> these routines require zwgc_active to be false (0)
154 #define BATCH_SIZE 20
156 static int subscription_list_size = 0;
157 static ZSubscription_t subscription_list[BATCH_SIZE];
159 static int unsubscription_list_size = 0;
160 static ZSubscription_t unsubscription_list[BATCH_SIZE];
163 free_subscription_list(ZSubscription_t *list,
164 int number_of_elements)
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);
176 flush_subscriptions(void)
178 TRAP(ZSubscribeTo(subscription_list,subscription_list_size, 0),
179 "while subscribing");
181 free_subscription_list(subscription_list, subscription_list_size);
182 subscription_list_size = 0;
186 flush_unsubscriptions(void)
188 if (unsubscription_list_size)
189 TRAP(ZUnsubscribeTo(unsubscription_list, unsubscription_list_size, 0),
190 "while unsubscribing");
192 free_subscription_list(unsubscription_list, unsubscription_list_size);
193 unsubscription_list_size = 0;
197 subscribe(string class,
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);
205 if (++subscription_list_size == BATCH_SIZE)
206 flush_subscriptions();
210 unsubscribe(string class,
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);
220 if (++unsubscription_list_size == BATCH_SIZE)
221 flush_unsubscriptions();
224 /****************************************************************************/
226 /* Code to implement reading [un]subscriptions from a file: */
228 /****************************************************************************/
230 #define TOKEN_HOSTNAME "%host%"
231 #define TOKEN_CANONNAME "%canon%"
232 #define TOKEN_ME "%me%"
233 #define TOKEN_WILD "*"
235 char ourhost[NS_MAXDNAME], ourhostcanon[NS_MAXDNAME];
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);
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);
251 strncpy(ourhostcanon, hent->h_name, sizeof(ourhostcanon)-1);
258 static int initedhosts = 0;
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);
272 #define UNSUBSCRIBE_CHARACTER '!'
273 #define PUNT_CHARACTER '-'
276 load_subscriptions_from_file(FILE *file)
279 char class_buffer[BUFSIZ], instance[BUFSIZ], recipient[BUFSIZ];
283 while ((!feof(file)) && (!ferror(file))) {
284 if (fgets(line, BUFSIZ, file)) {
285 class = class_buffer;
288 * The below does NOT work is the recipient field is "":
290 temp = strchr(line, '#');
293 for (temp=line; *temp && *temp==' '; temp++) ;
294 if (!*temp || *temp=='\n')
297 sscanf(temp,"%[^,],%[^,],%s", class, instance, recipient);
299 /* skip type indicator if any: */
301 if (c==UNSUBSCRIBE_CHARACTER || c==PUNT_CHARACTER)
304 /* perform macro substitutions */
307 macro_sub(recipient);
309 /* do the right thing with it */
311 case UNSUBSCRIBE_CHARACTER:
312 unsubscribe(class, instance, recipient);
315 punt(class, instance, recipient);
318 subscribe(class, instance, recipient);
327 com_err("zwgc", errno, "while reading from subscription file");
331 flush_subscriptions();
332 flush_unsubscriptions();
337 #define DEFSUBS "/dev/null"
340 load_subscriptions(void)
342 FILE *subscriptions_file;
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,
349 if (subscriptions_file)
350 load_subscriptions_from_file(subscriptions_file);
353 /****************************************************************************/
355 /* Code to implement shutdown and startup: */
357 /****************************************************************************/
361 static ZSubscription_t *saved_subscriptions = NULL;
362 static int number_of_saved_subscriptions;
364 void zwgc_shutdown(void)
369 TRAP(ZRetrieveSubscriptions(0, &number_of_saved_subscriptions),
370 "while retrieving zephyr subscription list");
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");
380 free(saved_subscriptions);
381 saved_subscriptions = NULL;
383 TRAP(ZCancelSubscriptions(0), "while canceling subscriptions") ;
388 void zwgc_startup(void)
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;
399 load_subscriptions();