]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/zwgc/subscriptions.c
finalize -3
[1ts-debian.git] / zephyr / zwgc / 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$
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 char rcsid_subscriptions_c[] = "$Id$";
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 "new_memory.h"
28 #include "new_string.h"
29 #include "int_dictionary.h"
30 #include "zwgc.h"
31 #include "subscriptions.h"
32 #include "error.h"
33 #include "file.h"
34 #include "main.h"
35
36 /****************************************************************************/
37 /*                                                                          */
38 /*                  Code to implement punting of notices:                   */
39 /*                                                                          */
40 /****************************************************************************/
41
42 /*
43  *
44  */
45 static int_dictionary puntable_addresses_dict = 0;
46
47 static void init_puntable_dict()
48 {
49     puntable_addresses_dict = int_dictionary_Create(33);
50 }
51
52 static string address_to_string(class, instance, recipient)
53      string class;
54      string instance;
55      string recipient;
56 {
57     string result;
58
59     /*
60      * Treat a recipient of "" as "*":
61      */
62     if (string_Eq(recipient,""))
63       recipient = "*";
64
65     /*
66      * The following is a hack for now only.  It should be replaced with
67      * several calls to escape_code... <<<>>>
68      */
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);
74
75     return(result);
76 }
77
78 int puntable_address_p(class, instance, recipient)
79      string class;
80      string instance;
81      string recipient;
82 {
83     string temp;
84
85     if (!puntable_addresses_dict)
86       init_puntable_dict();
87
88     temp = address_to_string(class, instance, recipient);
89     if (int_dictionary_Lookup(puntable_addresses_dict, temp)) {
90         free(temp);
91         return(1);
92     }
93
94     free(temp);
95     return(0);
96 }
97
98 void punt(class, instance, recipient)
99      string class;
100      string instance;
101      string recipient;
102 {
103     string temp;
104
105     if (!puntable_addresses_dict)
106       init_puntable_dict();
107
108     temp = address_to_string(class, instance, recipient);
109     (void)int_dictionary_Define(puntable_addresses_dict, temp, 0);
110     free(temp);
111 }
112
113 void unpunt(class, instance, recipient)
114      string class;
115      string instance;
116      string recipient;
117 {
118     string temp;
119     int_dictionary_binding *binding;
120
121     if (!puntable_addresses_dict)
122       init_puntable_dict();
123
124     temp = address_to_string(class, instance, recipient);
125     binding = int_dictionary_Define(puntable_addresses_dict, temp, 0);
126     free(temp);
127     if (binding)
128       int_dictionary_Delete(puntable_addresses_dict, binding);
129 }
130
131 /****************************************************************************/
132 /*                                                                          */
133 /*           Code to implement batching [un]subscription requests:          */
134 /*                                                                          */
135 /****************************************************************************/
136
137 /*
138  * <<<>>> these routines require zwgc_active to be false (0)
139  */
140
141 #define  BATCH_SIZE   20
142
143 static int subscription_list_size = 0;
144 static ZSubscription_t subscription_list[BATCH_SIZE];
145
146 static int unsubscription_list_size = 0;
147 static ZSubscription_t unsubscription_list[BATCH_SIZE];
148
149 static void free_subscription_list(list, number_of_elements)
150      ZSubscription_t *list;
151      int number_of_elements;
152 {
153     int i;
154
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);
159     }
160 }
161
162 static void flush_subscriptions()
163 {
164       TRAP(ZSubscribeTo(subscription_list,subscription_list_size, 0),
165            "while subscribing");
166
167     free_subscription_list(subscription_list, subscription_list_size);
168     subscription_list_size = 0;
169 }
170
171 static void flush_unsubscriptions()
172 {
173     if (unsubscription_list_size)
174       TRAP(ZUnsubscribeTo(unsubscription_list, unsubscription_list_size, 0),
175            "while unsubscribing");
176
177     free_subscription_list(unsubscription_list, unsubscription_list_size);
178     unsubscription_list_size = 0;
179 }
180
181 static void subscribe(class, instance, recipient)
182      string class;
183      string instance;
184      string recipient;
185 {
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);
189
190     if (++subscription_list_size == BATCH_SIZE)
191       flush_subscriptions();
192 }
193
194 static void unsubscribe(class, instance, recipient)
195      string class;
196      string instance;
197      string recipient;
198 {
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);
204
205     if (++unsubscription_list_size == BATCH_SIZE)
206       flush_unsubscriptions();
207 }
208
209 /****************************************************************************/
210 /*                                                                          */
211 /*         Code to implement reading [un]subscriptions from a file:         */
212 /*                                                                          */
213 /****************************************************************************/
214
215 #define TOKEN_HOSTNAME  "%host%"
216 #define TOKEN_CANONNAME "%canon%"
217 #define TOKEN_ME        "%me%"
218 #define TOKEN_WILD      "*"
219
220 char ourhost[MAXHOSTNAMELEN],ourhostcanon[MAXHOSTNAMELEN];
221
222 static void inithosts()
223 {
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);
227         return;
228     }
229
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);
233         return;
234     }
235     strncpy(ourhostcanon, hent->h_name, sizeof(ourhostcanon)-1);
236     return;
237 }
238
239 static void macro_sub(str)
240      char *str;
241 {
242     static int initedhosts = 0;
243
244     if (!initedhosts) {
245         inithosts();
246         initedhosts = 1;
247     }
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);
254 }
255
256 #define  UNSUBSCRIBE_CHARACTER  '!'
257 #define  PUNT_CHARACTER         '-'
258
259 static void load_subscriptions_from_file(file)
260      FILE *file;
261 {
262     char line[BUFSIZ];
263     char class_buffer[BUFSIZ], instance[BUFSIZ], recipient[BUFSIZ];
264     char *class, *temp;
265     char c;
266    
267     while ((!feof(file)) && (!ferror(file))) {
268         if (fgets(line, BUFSIZ, file)) {
269             class = class_buffer;
270             /* Parse line */
271             /* <<<>>>
272              * The below does NOT work is the recipient field  is "":
273              */ 
274             if (temp = strchr(line, '#'))
275               *temp = '\0';
276             for (temp=line; *temp && *temp==' '; temp++) ;
277             if (!*temp || *temp=='\n')
278               continue;
279
280             sscanf(temp,"%[^,],%[^,],%s", class, instance, recipient);
281
282             /* skip type indicator if any: */
283             c = class[0];
284             if (c==UNSUBSCRIBE_CHARACTER || c==PUNT_CHARACTER)
285               class++;
286             
287             /* perform macro substitutions */
288             macro_sub(class);
289             macro_sub(instance);
290             macro_sub(recipient);
291             
292             /* do the right thing with it */
293             switch (c) {
294               case UNSUBSCRIBE_CHARACTER:
295                 unsubscribe(class, instance, recipient);
296                 break;
297               case PUNT_CHARACTER:
298                 punt(class, instance, recipient);
299                 break;
300               default:
301                 subscribe(class, instance, recipient);
302                 break;
303             }
304         } else {
305             break;
306         }
307     }
308     
309     if (ferror(file)) {
310         com_err("zwgc", errno, "while reading from subscription file");
311         exit(1);
312     }
313
314     flush_subscriptions();
315     flush_unsubscriptions();
316     
317     fclose(file);
318 }
319
320 #define DEFSUBS "/dev/null"
321
322 static void load_subscriptions()
323 {
324     FILE *subscriptions_file;
325
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,
330                                      USRSUBS, DEFSUBS);
331     if (subscriptions_file)
332       load_subscriptions_from_file(subscriptions_file);
333 }
334
335 /****************************************************************************/
336 /*                                                                          */
337 /*                Code to implement shutdown and startup:                   */
338 /*                                                                          */
339 /****************************************************************************/
340
341 int zwgc_active = 0;
342
343 static ZSubscription_t *saved_subscriptions = NULL;
344 static int number_of_saved_subscriptions;
345
346 void zwgc_shutdown()
347 {
348     if (!zwgc_active)
349       return;
350
351     TRAP(ZRetrieveSubscriptions(0, &number_of_saved_subscriptions),
352          "while retrieving zephyr subscription list");
353     if (error_code)
354       return;
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");
361     if (error_code) {
362         free(saved_subscriptions);
363         saved_subscriptions = NULL;
364     }
365     TRAP(ZCancelSubscriptions(0), "while canceling subscriptions") ;
366
367     zwgc_active = 0;
368 }
369
370 void zwgc_startup()
371 {
372     if (zwgc_active)
373       return;
374
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;
380     } else
381       load_subscriptions();
382
383     zwgc_active = 1;
384 }