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,v 1.14 2003/11/04 19:22:06 ghudson Exp $
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 char rcsid_subscriptions_c[] = "$Id: subscriptions.c,v 1.14 2003/11/04 19:22:06 ghudson Exp $";
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;
47 static void init_puntable_dict()
49 puntable_addresses_dict = int_dictionary_Create(33);
52 static string address_to_string(class, instance, recipient)
60 * Treat a recipient of "" as "*":
62 if (string_Eq(recipient,""))
66 * The following is a hack for now only. It should be replaced with
67 * several calls to escape_code... <<<>>>
69 result = string_Concat(class, "\001");
70 result = string_Concat2(result, instance);
71 result = string_Concat2(result, "\001");
72 result = string_Concat2(result, recipient);
73 string_Downcase(result);
78 int puntable_address_p(class, instance, recipient)
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(class, instance, recipient)
105 if (!puntable_addresses_dict)
106 init_puntable_dict();
108 temp = address_to_string(class, instance, recipient);
109 (void)int_dictionary_Define(puntable_addresses_dict, temp, 0);
113 void unpunt(class, instance, recipient)
119 int_dictionary_binding *binding;
121 if (!puntable_addresses_dict)
122 init_puntable_dict();
124 temp = address_to_string(class, instance, recipient);
125 binding = int_dictionary_Define(puntable_addresses_dict, temp, 0);
128 int_dictionary_Delete(puntable_addresses_dict, binding);
131 /****************************************************************************/
133 /* Code to implement batching [un]subscription requests: */
135 /****************************************************************************/
138 * <<<>>> these routines require zwgc_active to be false (0)
141 #define BATCH_SIZE 20
143 static int subscription_list_size = 0;
144 static ZSubscription_t subscription_list[BATCH_SIZE];
146 static int unsubscription_list_size = 0;
147 static ZSubscription_t unsubscription_list[BATCH_SIZE];
149 static void free_subscription_list(list, number_of_elements)
150 ZSubscription_t *list;
151 int number_of_elements;
155 for (i=0; i<number_of_elements; i++) {
156 free(list[i].zsub_class);
157 free(list[i].zsub_classinst);
158 free(list[i].zsub_recipient);
162 static void flush_subscriptions()
164 TRAP(ZSubscribeTo(subscription_list,subscription_list_size, 0),
165 "while subscribing");
167 free_subscription_list(subscription_list, subscription_list_size);
168 subscription_list_size = 0;
171 static void flush_unsubscriptions()
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;
181 static void subscribe(class, instance, recipient)
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();
194 static void unsubscribe(class, instance, recipient)
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];
222 static void inithosts()
224 struct hostent *hent;
225 if (gethostname(ourhost, sizeof(ourhost)-1) == -1) {
226 ERROR3("unable to retrieve hostname, %s and %s will be wrong in subscriptions.\n", TOKEN_HOSTNAME, TOKEN_CANONNAME);
230 if (!(hent = gethostbyname(ourhost))) {
231 ERROR2("unable to resolve hostname, %s will be wrong in subscriptions.\n", TOKEN_CANONNAME);
232 strncpy(ourhostcanon, ourhost, sizeof(ourhostcanon)-1);
235 strncpy(ourhostcanon, hent->h_name, sizeof(ourhostcanon)-1);
239 static void macro_sub(str)
242 static int initedhosts = 0;
248 if (string_Eq(str, TOKEN_ME))
249 strcpy(str, ZGetSender());
250 else if (string_Eq(str, TOKEN_HOSTNAME))
251 strcpy(str, ourhost);
252 else if (string_Eq(str, TOKEN_CANONNAME))
253 strcpy(str, ourhostcanon);
256 #define UNSUBSCRIBE_CHARACTER '!'
257 #define PUNT_CHARACTER '-'
259 static void load_subscriptions_from_file(file)
263 char class_buffer[BUFSIZ], instance[BUFSIZ], recipient[BUFSIZ];
267 while ((!feof(file)) && (!ferror(file))) {
268 if (fgets(line, BUFSIZ, file)) {
269 class = class_buffer;
272 * The below does NOT work is the recipient field is "":
274 if (temp = strchr(line, '#'))
276 for (temp=line; *temp && *temp==' '; temp++) ;
277 if (!*temp || *temp=='\n')
280 sscanf(temp,"%[^,],%[^,],%s", class, instance, recipient);
282 /* skip type indicator if any: */
284 if (c==UNSUBSCRIBE_CHARACTER || c==PUNT_CHARACTER)
287 /* perform macro substitutions */
290 macro_sub(recipient);
292 /* do the right thing with it */
294 case UNSUBSCRIBE_CHARACTER:
295 unsubscribe(class, instance, recipient);
298 punt(class, instance, recipient);
301 subscribe(class, instance, recipient);
310 com_err("zwgc", errno, "while reading from subscription file");
314 flush_subscriptions();
315 flush_unsubscriptions();
320 #define DEFSUBS "/dev/null"
322 static void load_subscriptions()
324 FILE *subscriptions_file;
326 /* no system default sub file on client--they live on the server */
327 /* BUT...we need to use something to call load_subscriptions_from_file,
328 so we use /dev/null */
329 subscriptions_file = locate_file(subscriptions_filename_override,
331 if (subscriptions_file)
332 load_subscriptions_from_file(subscriptions_file);
335 /****************************************************************************/
337 /* Code to implement shutdown and startup: */
339 /****************************************************************************/
343 static ZSubscription_t *saved_subscriptions = NULL;
344 static int number_of_saved_subscriptions;
351 TRAP(ZRetrieveSubscriptions(0, &number_of_saved_subscriptions),
352 "while retrieving zephyr subscription list");
355 saved_subscriptions = (ZSubscription_t *)
356 malloc(number_of_saved_subscriptions*sizeof(ZSubscription_t));
357 if (number_of_saved_subscriptions)
358 TRAP(ZGetSubscriptions(saved_subscriptions,
359 &number_of_saved_subscriptions),
360 "while getting subscriptions");
362 free(saved_subscriptions);
363 saved_subscriptions = NULL;
365 TRAP(ZCancelSubscriptions(0), "while canceling subscriptions") ;
375 if (saved_subscriptions) {
376 TRAP(ZSubscribeToSansDefaults(saved_subscriptions,number_of_saved_subscriptions,0),
377 "while resubscribing to zephyr messages");
378 free(saved_subscriptions);
379 saved_subscriptions = NULL;
381 load_subscriptions();