ratatoskr-messenger/zwgc/subscriptions.c

403 lines
11 KiB
C

/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#if (!defined(lint) && !defined(SABER))
static const char rcsid_subscriptions_c[] = "$Id$";
#endif
/****************************************************************************/
/* */
/* Subscriptions.c: code to deal with subscriptions & punting: */
/* */
/****************************************************************************/
#include <sysdep.h>
#include <zephyr/zephyr.h>
#include <netdb.h>
#include <arpa/nameser.h>
#include "new_memory.h"
#include "new_string.h"
#include "int_dictionary.h"
#include "zwgc.h"
#include "subscriptions.h"
#include "error.h"
#include "file.h"
#include "main.h"
/****************************************************************************/
/* */
/* Code to implement punting of notices: */
/* */
/****************************************************************************/
/*
*
*/
#ifndef CMU_ZCTL_PUNT
static
#endif
int_dictionary puntable_addresses_dict = 0;
static void
init_puntable_dict(void)
{
puntable_addresses_dict = int_dictionary_Create(33);
}
static string
address_to_string(string class,
string instance,
string recipient)
{
string result;
/*
* Treat a recipient of "" as "*":
*/
if (string_Eq(recipient,""))
recipient = "*";
else if (recipient[0] == '@') {
recipient = string_Concat("*", recipient);
}
/*
* The following is a hack for now only. It should be replaced with
* several calls to escape_code... <<<>>>
*/
result = string_Concat(class, "\001");
result = string_Concat2(result, instance);
result = string_Concat2(result, "\001");
result = string_Concat2(result, recipient);
string_Downcase(result);
return(result);
}
int puntable_address_p(string class,
string instance,
string recipient)
{
string temp;
if (!puntable_addresses_dict)
init_puntable_dict();
temp = address_to_string(class, instance, recipient);
if (int_dictionary_Lookup(puntable_addresses_dict, temp)) {
free(temp);
return 1;
}
free(temp);
/* This kludge is to allow punts of wildcard instance to work */
temp = address_to_string(class, "*", recipient);
if (int_dictionary_Lookup(puntable_addresses_dict, temp)) {
free(temp);
return(1);
}
free(temp);
return(0);
}
void punt(string class,
string instance,
string recipient)
{
string temp;
if (!puntable_addresses_dict)
init_puntable_dict();
temp = address_to_string(class, instance, recipient);
(void)int_dictionary_Define(puntable_addresses_dict, temp, 0);
free(temp);
}
void unpunt(string class,
string instance,
string recipient)
{
string temp;
int_dictionary_binding *binding;
if (!puntable_addresses_dict)
init_puntable_dict();
temp = address_to_string(class, instance, recipient);
binding = int_dictionary_Define(puntable_addresses_dict, temp, 0);
free(temp);
if (binding)
int_dictionary_Delete(puntable_addresses_dict, binding);
}
/****************************************************************************/
/* */
/* Code to implement batching [un]subscription requests: */
/* */
/****************************************************************************/
/*
* <<<>>> these routines require zwgc_active to be false (0)
*/
#define BATCH_SIZE 20
static int subscription_list_size = 0;
static ZSubscription_t subscription_list[BATCH_SIZE];
static int unsubscription_list_size = 0;
static ZSubscription_t unsubscription_list[BATCH_SIZE];
static void
free_subscription_list(ZSubscription_t *list,
int number_of_elements)
{
int i;
for (i=0; i<number_of_elements; i++) {
free(list[i].zsub_class);
free(list[i].zsub_classinst);
free(list[i].zsub_recipient);
}
}
static void
flush_subscriptions(void)
{
TRAP(ZSubscribeTo(subscription_list,subscription_list_size, 0),
"while subscribing");
free_subscription_list(subscription_list, subscription_list_size);
subscription_list_size = 0;
}
static void
flush_unsubscriptions(void)
{
if (unsubscription_list_size)
TRAP(ZUnsubscribeTo(unsubscription_list, unsubscription_list_size, 0),
"while unsubscribing");
free_subscription_list(unsubscription_list, unsubscription_list_size);
unsubscription_list_size = 0;
}
static void
subscribe(string class,
string instance,
string recipient)
{
subscription_list[subscription_list_size].zsub_class = string_Copy(class);
subscription_list[subscription_list_size].zsub_classinst= string_Copy(instance);
subscription_list[subscription_list_size].zsub_recipient=string_Copy(recipient);
if (++subscription_list_size == BATCH_SIZE)
flush_subscriptions();
}
static void
unsubscribe(string class,
string instance,
string recipient)
{
unsubscription_list[unsubscription_list_size].zsub_class = string_Copy(class);
unsubscription_list[unsubscription_list_size].zsub_classinst
= string_Copy(instance);
unsubscription_list[unsubscription_list_size].zsub_recipient
= string_Copy(recipient);
if (++unsubscription_list_size == BATCH_SIZE)
flush_unsubscriptions();
}
/****************************************************************************/
/* */
/* Code to implement reading [un]subscriptions from a file: */
/* */
/****************************************************************************/
#define TOKEN_HOSTNAME "%host%"
#define TOKEN_CANONNAME "%canon%"
#define TOKEN_ME "%me%"
#define TOKEN_WILD "*"
char ourhost[NS_MAXDNAME], ourhostcanon[NS_MAXDNAME];
static void
inithosts(void)
{
struct hostent *hent;
if (gethostname(ourhost, sizeof(ourhost)-1) == -1) {
ERROR3("unable to retrieve hostname, %s and %s will be wrong in subscriptions.\n", TOKEN_HOSTNAME, TOKEN_CANONNAME);
return;
}
if (!(hent = gethostbyname(ourhost))) {
ERROR2("unable to resolve hostname, %s will be wrong in subscriptions.\n", TOKEN_CANONNAME);
strncpy(ourhostcanon, ourhost, sizeof(ourhostcanon)-1);
return;
}
strncpy(ourhostcanon, hent->h_name, sizeof(ourhostcanon)-1);
return;
}
static void
macro_sub(char *str)
{
static int initedhosts = 0;
if (!initedhosts) {
inithosts();
initedhosts = 1;
}
if (string_Eq(str, TOKEN_ME))
strcpy(str, ZGetSender());
else if (string_Eq(str, TOKEN_HOSTNAME))
strcpy(str, ourhost);
else if (string_Eq(str, TOKEN_CANONNAME))
strcpy(str, ourhostcanon);
}
#define UNSUBSCRIBE_CHARACTER '!'
#define PUNT_CHARACTER '-'
static void
load_subscriptions_from_file(FILE *file)
{
char line[BUFSIZ];
char class_buffer[BUFSIZ], instance[BUFSIZ], recipient[BUFSIZ];
char *class, *temp;
char c;
while ((!feof(file)) && (!ferror(file))) {
if (fgets(line, BUFSIZ, file)) {
class = class_buffer;
/* Parse line */
/* <<<>>>
* The below does NOT work is the recipient field is "":
*/
temp = strchr(line, '#');
if (temp)
*temp = '\0';
for (temp=line; *temp && *temp==' '; temp++) ;
if (!*temp || *temp=='\n')
continue;
sscanf(temp,"%[^,],%[^,],%s", class, instance, recipient);
/* skip type indicator if any: */
c = class[0];
if (c==UNSUBSCRIBE_CHARACTER || c==PUNT_CHARACTER)
class++;
/* perform macro substitutions */
macro_sub(class);
macro_sub(instance);
macro_sub(recipient);
/* do the right thing with it */
switch (c) {
case UNSUBSCRIBE_CHARACTER:
unsubscribe(class, instance, recipient);
break;
case PUNT_CHARACTER:
punt(class, instance, recipient);
break;
default:
subscribe(class, instance, recipient);
break;
}
} else {
break;
}
}
if (ferror(file)) {
com_err("zwgc", errno, "while reading from subscription file");
exit(1);
}
flush_subscriptions();
flush_unsubscriptions();
fclose(file);
}
#define DEFSUBS "/dev/null"
static void
load_subscriptions(void)
{
FILE *subscriptions_file;
/* no system default sub file on client--they live on the server */
/* BUT...we need to use something to call load_subscriptions_from_file,
so we use /dev/null */
subscriptions_file = locate_file(subscriptions_filename_override,
USRSUBS, DEFSUBS);
if (subscriptions_file)
load_subscriptions_from_file(subscriptions_file);
}
/****************************************************************************/
/* */
/* Code to implement shutdown and startup: */
/* */
/****************************************************************************/
int zwgc_active = 0;
static ZSubscription_t *saved_subscriptions = NULL;
static int number_of_saved_subscriptions;
void zwgc_shutdown(void)
{
if (!zwgc_active)
return;
TRAP(ZRetrieveSubscriptions(0, &number_of_saved_subscriptions),
"while retrieving zephyr subscription list");
if (error_code)
return;
saved_subscriptions = (ZSubscription_t *)
malloc(number_of_saved_subscriptions*sizeof(ZSubscription_t));
if (number_of_saved_subscriptions)
TRAP(ZGetSubscriptions(saved_subscriptions,
&number_of_saved_subscriptions),
"while getting subscriptions");
if (error_code) {
free(saved_subscriptions);
saved_subscriptions = NULL;
}
TRAP(ZCancelSubscriptions(0), "while canceling subscriptions") ;
zwgc_active = 0;
}
void zwgc_startup(void)
{
if (zwgc_active)
return;
if (saved_subscriptions) {
TRAP(ZSubscribeToSansDefaults(saved_subscriptions,number_of_saved_subscriptions,0),
"while resubscribing to zephyr messages");
free(saved_subscriptions);
saved_subscriptions = NULL;
} else
load_subscriptions();
zwgc_active = 1;
}