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>
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$";
18 /****************************************************************************/
20 /* Subscriptions.c: code to deal with subscriptions & punting: */
22 /****************************************************************************/
25 #include <zephyr/zephyr.h>
27 #include "new_memory.h"
28 #include "new_string.h"
29 #include "int_dictionary.h"
31 #include "subscriptions.h"
36 /****************************************************************************/
38 /* Code to implement punting of notices: */
40 /****************************************************************************/
45 static int_dictionary puntable_addresses_dict = 0;
48 init_puntable_dict(void)
50 puntable_addresses_dict = int_dictionary_Create(33);
54 address_to_string(string class,
61 * Treat a recipient of "" as "*":
63 if (string_Eq(recipient,""))
67 * The following is a hack for now only. It should be replaced with
68 * several calls to escape_code... <<<>>>
70 result = string_Concat(class, "\001");
71 result = string_Concat2(result, instance);
72 result = string_Concat2(result, "\001");
73 result = string_Concat2(result, recipient);
74 string_Downcase(result);
79 int puntable_address_p(string class,
85 if (!puntable_addresses_dict)
88 temp = address_to_string(class, instance, recipient);
89 if (int_dictionary_Lookup(puntable_addresses_dict, temp)) {
98 void punt(string class,
104 if (!puntable_addresses_dict)
105 init_puntable_dict();
107 temp = address_to_string(class, instance, recipient);
108 (void)int_dictionary_Define(puntable_addresses_dict, temp, 0);
112 void unpunt(string class,
117 int_dictionary_binding *binding;
119 if (!puntable_addresses_dict)
120 init_puntable_dict();
122 temp = address_to_string(class, instance, recipient);
123 binding = int_dictionary_Define(puntable_addresses_dict, temp, 0);
126 int_dictionary_Delete(puntable_addresses_dict, binding);
129 /****************************************************************************/
131 /* Code to implement batching [un]subscription requests: */
133 /****************************************************************************/
136 * <<<>>> these routines require zwgc_active to be false (0)
139 #define BATCH_SIZE 20
141 static int subscription_list_size = 0;
142 static ZSubscription_t subscription_list[BATCH_SIZE];
144 static int unsubscription_list_size = 0;
145 static ZSubscription_t unsubscription_list[BATCH_SIZE];
148 free_subscription_list(ZSubscription_t *list,
149 int number_of_elements)
153 for (i=0; i<number_of_elements; i++) {
154 free(list[i].zsub_class);
155 free(list[i].zsub_classinst);
156 free(list[i].zsub_recipient);
161 flush_subscriptions(void)
163 TRAP(ZSubscribeTo(subscription_list,subscription_list_size, 0),
164 "while subscribing");
166 free_subscription_list(subscription_list, subscription_list_size);
167 subscription_list_size = 0;
171 flush_unsubscriptions(void)
173 if (unsubscription_list_size)
174 TRAP(ZUnsubscribeTo(unsubscription_list, unsubscription_list_size, 0),
175 "while unsubscribing");
177 free_subscription_list(unsubscription_list, unsubscription_list_size);
178 unsubscription_list_size = 0;
182 subscribe(string class,
186 subscription_list[subscription_list_size].zsub_class = string_Copy(class);
187 subscription_list[subscription_list_size].zsub_classinst= string_Copy(instance);
188 subscription_list[subscription_list_size].zsub_recipient=string_Copy(recipient);
190 if (++subscription_list_size == BATCH_SIZE)
191 flush_subscriptions();
195 unsubscribe(string class,
199 unsubscription_list[unsubscription_list_size].zsub_class = string_Copy(class);
200 unsubscription_list[unsubscription_list_size].zsub_classinst
201 = string_Copy(instance);
202 unsubscription_list[unsubscription_list_size].zsub_recipient
203 = string_Copy(recipient);
205 if (++unsubscription_list_size == BATCH_SIZE)
206 flush_unsubscriptions();
209 /****************************************************************************/
211 /* Code to implement reading [un]subscriptions from a file: */
213 /****************************************************************************/
215 #define TOKEN_HOSTNAME "%host%"
216 #define TOKEN_CANONNAME "%canon%"
217 #define TOKEN_ME "%me%"
218 #define TOKEN_WILD "*"
220 char ourhost[MAXHOSTNAMELEN],ourhostcanon[MAXHOSTNAMELEN];
225 struct hostent *hent;
226 if (gethostname(ourhost, sizeof(ourhost)-1) == -1) {
227 ERROR3("unable to retrieve hostname, %s and %s will be wrong in subscriptions.\n", TOKEN_HOSTNAME, TOKEN_CANONNAME);
231 if (!(hent = gethostbyname(ourhost))) {
232 ERROR2("unable to resolve hostname, %s will be wrong in subscriptions.\n", TOKEN_CANONNAME);
233 strncpy(ourhostcanon, ourhost, sizeof(ourhostcanon)-1);
236 strncpy(ourhostcanon, hent->h_name, sizeof(ourhostcanon)-1);
243 static int initedhosts = 0;
249 if (string_Eq(str, TOKEN_ME))
250 strcpy(str, ZGetSender());
251 else if (string_Eq(str, TOKEN_HOSTNAME))
252 strcpy(str, ourhost);
253 else if (string_Eq(str, TOKEN_CANONNAME))
254 strcpy(str, ourhostcanon);
257 #define UNSUBSCRIBE_CHARACTER '!'
258 #define PUNT_CHARACTER '-'
261 load_subscriptions_from_file(FILE *file)
264 char class_buffer[BUFSIZ], instance[BUFSIZ], recipient[BUFSIZ];
268 while ((!feof(file)) && (!ferror(file))) {
269 if (fgets(line, BUFSIZ, file)) {
270 class = class_buffer;
273 * The below does NOT work is the recipient field is "":
275 temp = strchr(line, '#');
278 for (temp=line; *temp && *temp==' '; temp++) ;
279 if (!*temp || *temp=='\n')
282 sscanf(temp,"%[^,],%[^,],%s", class, instance, recipient);
284 /* skip type indicator if any: */
286 if (c==UNSUBSCRIBE_CHARACTER || c==PUNT_CHARACTER)
289 /* perform macro substitutions */
292 macro_sub(recipient);
294 /* do the right thing with it */
296 case UNSUBSCRIBE_CHARACTER:
297 unsubscribe(class, instance, recipient);
300 punt(class, instance, recipient);
303 subscribe(class, instance, recipient);
312 com_err("zwgc", errno, "while reading from subscription file");
316 flush_subscriptions();
317 flush_unsubscriptions();
322 #define DEFSUBS "/dev/null"
325 load_subscriptions(void)
327 FILE *subscriptions_file;
329 /* no system default sub file on client--they live on the server */
330 /* BUT...we need to use something to call load_subscriptions_from_file,
331 so we use /dev/null */
332 subscriptions_file = locate_file(subscriptions_filename_override,
334 if (subscriptions_file)
335 load_subscriptions_from_file(subscriptions_file);
338 /****************************************************************************/
340 /* Code to implement shutdown and startup: */
342 /****************************************************************************/
346 static ZSubscription_t *saved_subscriptions = NULL;
347 static int number_of_saved_subscriptions;
349 void zwgc_shutdown(void)
354 TRAP(ZRetrieveSubscriptions(0, &number_of_saved_subscriptions),
355 "while retrieving zephyr subscription list");
358 saved_subscriptions = (ZSubscription_t *)
359 malloc(number_of_saved_subscriptions*sizeof(ZSubscription_t));
360 if (number_of_saved_subscriptions)
361 TRAP(ZGetSubscriptions(saved_subscriptions,
362 &number_of_saved_subscriptions),
363 "while getting subscriptions");
365 free(saved_subscriptions);
366 saved_subscriptions = NULL;
368 TRAP(ZCancelSubscriptions(0), "while canceling subscriptions") ;
373 void zwgc_startup(void)
378 if (saved_subscriptions) {
379 TRAP(ZSubscribeToSansDefaults(saved_subscriptions,number_of_saved_subscriptions,0),
380 "while resubscribing to zephyr messages");
381 free(saved_subscriptions);
382 saved_subscriptions = NULL;
384 load_subscriptions();