]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/zwgc/subscriptions.c
r4275@bucket (orig r265): kcr | 2008-01-21 02:57:32 -0500
[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 const 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
48 init_puntable_dict(void)
49 {
50     puntable_addresses_dict = int_dictionary_Create(33);
51 }
52
53 static string
54 address_to_string(string class,
55                   string instance,
56                   string recipient)
57 {
58     string result;
59
60     /*
61      * Treat a recipient of "" as "*":
62      */
63     if (string_Eq(recipient,""))
64       recipient = "*";
65
66     /*
67      * The following is a hack for now only.  It should be replaced with
68      * several calls to escape_code... <<<>>>
69      */
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);
75
76     return(result);
77 }
78
79 int puntable_address_p(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(string class,
99           string instance,
100           string recipient)
101 {
102     string temp;
103
104     if (!puntable_addresses_dict)
105       init_puntable_dict();
106
107     temp = address_to_string(class, instance, recipient);
108     (void)int_dictionary_Define(puntable_addresses_dict, temp, 0);
109     free(temp);
110 }
111
112 void unpunt(string class,
113             string instance,
114             string recipient)
115 {
116     string temp;
117     int_dictionary_binding *binding;
118
119     if (!puntable_addresses_dict)
120       init_puntable_dict();
121
122     temp = address_to_string(class, instance, recipient);
123     binding = int_dictionary_Define(puntable_addresses_dict, temp, 0);
124     free(temp);
125     if (binding)
126       int_dictionary_Delete(puntable_addresses_dict, binding);
127 }
128
129 /****************************************************************************/
130 /*                                                                          */
131 /*           Code to implement batching [un]subscription requests:          */
132 /*                                                                          */
133 /****************************************************************************/
134
135 /*
136  * <<<>>> these routines require zwgc_active to be false (0)
137  */
138
139 #define  BATCH_SIZE   20
140
141 static int subscription_list_size = 0;
142 static ZSubscription_t subscription_list[BATCH_SIZE];
143
144 static int unsubscription_list_size = 0;
145 static ZSubscription_t unsubscription_list[BATCH_SIZE];
146
147 static void
148 free_subscription_list(ZSubscription_t *list,
149                        int number_of_elements)
150 {
151     int i;
152
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);
157     }
158 }
159
160 static void
161 flush_subscriptions(void)
162 {
163       TRAP(ZSubscribeTo(subscription_list,subscription_list_size, 0),
164            "while subscribing");
165
166     free_subscription_list(subscription_list, subscription_list_size);
167     subscription_list_size = 0;
168 }
169
170 static void
171 flush_unsubscriptions(void)
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
182 subscribe(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
195 unsubscribe(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
223 inithosts(void)
224 {
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);
228         return;
229     }
230
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);
234         return;
235     }
236     strncpy(ourhostcanon, hent->h_name, sizeof(ourhostcanon)-1);
237     return;
238 }
239
240 static void
241 macro_sub(char *str)
242 {
243     static int initedhosts = 0;
244
245     if (!initedhosts) {
246         inithosts();
247         initedhosts = 1;
248     }
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);
255 }
256
257 #define  UNSUBSCRIBE_CHARACTER  '!'
258 #define  PUNT_CHARACTER         '-'
259
260 static void
261 load_subscriptions_from_file(FILE *file)
262 {
263     char line[BUFSIZ];
264     char class_buffer[BUFSIZ], instance[BUFSIZ], recipient[BUFSIZ];
265     char *class, *temp;
266     char c;
267    
268     while ((!feof(file)) && (!ferror(file))) {
269         if (fgets(line, BUFSIZ, file)) {
270             class = class_buffer;
271             /* Parse line */
272             /* <<<>>>
273              * The below does NOT work is the recipient field  is "":
274              */
275             temp = strchr(line, '#');
276             if (temp)
277               *temp = '\0';
278             for (temp=line; *temp && *temp==' '; temp++) ;
279             if (!*temp || *temp=='\n')
280               continue;
281
282             sscanf(temp,"%[^,],%[^,],%s", class, instance, recipient);
283
284             /* skip type indicator if any: */
285             c = class[0];
286             if (c==UNSUBSCRIBE_CHARACTER || c==PUNT_CHARACTER)
287               class++;
288             
289             /* perform macro substitutions */
290             macro_sub(class);
291             macro_sub(instance);
292             macro_sub(recipient);
293             
294             /* do the right thing with it */
295             switch (c) {
296               case UNSUBSCRIBE_CHARACTER:
297                 unsubscribe(class, instance, recipient);
298                 break;
299               case PUNT_CHARACTER:
300                 punt(class, instance, recipient);
301                 break;
302               default:
303                 subscribe(class, instance, recipient);
304                 break;
305             }
306         } else {
307             break;
308         }
309     }
310     
311     if (ferror(file)) {
312         com_err("zwgc", errno, "while reading from subscription file");
313         exit(1);
314     }
315
316     flush_subscriptions();
317     flush_unsubscriptions();
318     
319     fclose(file);
320 }
321
322 #define DEFSUBS "/dev/null"
323
324 static void
325 load_subscriptions(void)
326 {
327     FILE *subscriptions_file;
328
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,
333                                      USRSUBS, DEFSUBS);
334     if (subscriptions_file)
335       load_subscriptions_from_file(subscriptions_file);
336 }
337
338 /****************************************************************************/
339 /*                                                                          */
340 /*                Code to implement shutdown and startup:                   */
341 /*                                                                          */
342 /****************************************************************************/
343
344 int zwgc_active = 0;
345
346 static ZSubscription_t *saved_subscriptions = NULL;
347 static int number_of_saved_subscriptions;
348
349 void zwgc_shutdown(void)
350 {
351     if (!zwgc_active)
352       return;
353
354     TRAP(ZRetrieveSubscriptions(0, &number_of_saved_subscriptions),
355          "while retrieving zephyr subscription list");
356     if (error_code)
357       return;
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");
364     if (error_code) {
365         free(saved_subscriptions);
366         saved_subscriptions = NULL;
367     }
368     TRAP(ZCancelSubscriptions(0), "while canceling subscriptions") ;
369
370     zwgc_active = 0;
371 }
372
373 void zwgc_startup(void)
374 {
375     if (zwgc_active)
376       return;
377
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;
383     } else
384       load_subscriptions();
385
386     zwgc_active = 1;
387 }