352 lines
9.0 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".
*/
#include <sysdep.h>
#if (!defined(lint) && !defined(SABER))
static const char rcsid_notice_c[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
/****************************************************************************/
/* */
/* Module containing code to extract a notice's fields: */
/* */
/****************************************************************************/
#include <zephyr/zephyr.h>
#include <arpa/inet.h>
#include "new_memory.h"
#include "error.h"
#include "variables.h"
#include "notice.h"
#ifdef CMU_ZWGCPLUS
#include <pwd.h>
#include "plus.h"
#endif
/*
* int count_nulls(char *data, int length)
* Requires: length>=0
* Effects: Returns the # of nulls in data[0]..data[length-1]
*/
int
count_nulls(char *data,
int length)
{
int count = 0;
for (; length; data++, length--)
if (!*data)
count++;
return(count);
}
/*
* string get_next_field(char **data_p, int *length_p)
* Requires: *length_p >= 0
* Modifies: *data_p, *length_p
* Effects: Treats (*data_p)[0], (*data_p)[1], ... (*data_p)[length-1]
* as a series of null-seperated fields. This function
* returns a copy of the first field on the heap. This
* string must eventually be freed. Also, *data_p is
* advanced and *length_p decreased so that another
* call to this procedure with the same arguments will
* return the second field. The next call will return
* the third field, etc. "" is returned if 0 fields
* remain. (this is the case when *length_p == 0)
*/
string
get_next_field(char **data_p,
int *length_p)
{
char *data = *data_p;
int length = *length_p;
char *ptr;
for (ptr=data; length; ptr++, length--)
if (!*ptr) {
*data_p = ptr+1;
*length_p = length-1;
return(string_Copy(data));
}
length = *length_p;
*data_p = ptr;
*length_p = 0;
return(string_CreateFromData(data, length));
}
/*
* string get_field(char *data, int length, int num)
* Requires: length>=0, num>0
* Effects: Treats data[0]..data[length-1] as a series of
* null-seperated fields. This function returns a copy of
* the num'th field (numbered from 1 in this case) on the
* heap. This string must eventually be freed. If there
* is no num'th field (because num<1 or num># of fields),
* "" is returned.
*/
string get_field(char *data,
int length,
int num)
{
/*
* While num>1 and there are fields left, skip a field & decrement num:
*/
while (length && num>1) {
if (!*data)
num--;
length--;
data++;
}
/*
* If any more fields left, the first field is the one we want.
* Otherwise, there is no such field as num -- return "".
*/
if (length)
return(get_next_field(&data, &length));
else
return(string_Copy(""));
}
/*
* string convert_nulls_to_newlines(data, length)
* Requires: length>=0, malloc never returns NULL
* Effects: Takes data[0]..data[length-1], converts all nulls to
* newlines ('\n') and returns the result as a null-terminated
* string on the heap. The returned string must eventually
* be freed.
*/
string
convert_nulls_to_newlines(char *data,
int length)
{
char *result, *ptr;
char c;
result = (char *) malloc(length+1);
result[length] = '\0';
for (ptr=result; length; data++, ptr++, length--)
*ptr = (c = *data) ? c : '\n';
return(result);
}
/*
* Internal Routine:
*
* string z_kind_to_ascii(ZNotice_Kind_t z_kind)
* Effects: Returns an ascii representation for z_kind.
* The string returned is on the heap and must be freed
* eventually.
*/
static string
z_kind_to_ascii(ZNotice_Kind_t z_kind)
{
string result;
switch (z_kind) {
case UNSAFE:
result = "unsafe";
break;
case UNACKED:
result = "unacked";
break;
case ACKED:
result = "acked";
break;
case HMACK:
result = "hmack";
break;
case HMCTL:
result = "hmctl";
break;
case SERVACK:
result = "servack";
break;
case SERVNAK:
result = "servnak";
break;
case CLIENTACK:
result = "clientack";
break;
case STAT:
result = "stat";
break;
default:
result = "<unknown kind>";
break;
}
return(string_Copy(result));
}
/*
* Internal Routine:
*
* string z_auth_to_ascii(int z_auth)
* Effects: Returns an ascii representation for z_auth.
* The string returned is on the heap and must be freed
* eventually.
*/
static string
z_auth_to_ascii(int z_auth)
{
string result;
switch (z_auth) {
case ZAUTH_FAILED:
result = "forged";
break;
case ZAUTH_NO:
result = "no";
break;
case ZAUTH_YES:
result = "yes";
break;
default:
result = "unknown";
break;
}
return(string_Copy(result));
}
/*
* char *decode_notice(ZNotice_t *notice)
* Modifies: various description language variables
* Effects:
*/
char *
decode_notice(ZNotice_t *notice,
char *hostname)
{
char *temp;
string when, notyear, year, date_string, time_string;
/*
* Convert useful notice fields to ascii and store away in
* description language variables for later use by the
* the user's program:
*/
var_set_variable("zephyr_version", notice->z_version);
var_set_variable("class", notice->z_class);
var_set_variable("instance", notice->z_class_inst);
var_set_variable("opcode", notice->z_opcode);
var_set_variable("default", notice->z_default_format);
var_set_variable("notice_charset", (char *)ZCharsetToString(notice->z_charset)); /*XXX const*/
var_set_variable("recipient",
(notice->z_recipient[0] ? notice->z_recipient : "*"));
var_set_variable("fullsender", notice->z_sender);
var_set_variable_to_number("port", (int)ntohs(notice->z_port));
var_set_variable_then_free_value("kind", z_kind_to_ascii(notice->z_kind));
var_set_variable_then_free_value("auth", z_auth_to_ascii(notice->z_auth));
#ifdef CMU_ZWGCPLUS
if ((temp=getSelectedText()) != 0)
var_set_variable("selection", temp);
var_set_variable("delete_window", "none");
var_set_variable("event_time", "none");
var_set_variable("event_name", "event");
#endif
/*
* Set $sender to the name of the notice sender except first strip off the
* realm name if it is the local realm:
*/
if ( (temp=strchr(notice->z_sender,'@')) && string_Eq(temp+1, ZGetRealm()) )
var_set_variable_then_free_value("sender",
string_CreateFromData(notice->z_sender,
temp-notice->z_sender));
else
var_set_variable("sender", notice->z_sender);
#ifdef CMU_ZWGCPLUS
if (get_full_names) {
struct passwd *pwnam = getpwnam(var_get_variable("sender"));
if (pwnam) {
temp = string_Copy(pwnam->pw_gecos);
var_set_variable_then_free_value("sendername", temp);
} else {
var_set_variable("sendername", "unknown");
}
}
#endif
/*
* Convert time & date notice was sent to ascii. The $time
* has the format "01:03:52" while $date has the format
* "Sun Sep 16 1973".
*/
{
/* the fields of struct timeval might not be the right type to pass
to ctime, so use a temporary */
time_t sec = notice->z_time.tv_sec;
when = ctime(&sec);
}
time_string = string_CreateFromData(when+11,8);
var_set_variable_then_free_value("time", time_string);
date_string = string_Concat(notyear=string_CreateFromData(when,11),
year=string_CreateFromData(when+20,4));
var_set_variable_then_free_value("date", date_string);
free(notyear);
free(year);
/*
* Convert host notice sent from to ascii:
*/
var_set_variable("fromhost", hostname ? hostname :
inet_ntoa(notice->z_sender_addr));
/*
* Set $message to the message field of the notice with nulls changed
* to newlines:
*/
var_set_variable_then_free_value("message",
convert_nulls_to_newlines(notice->z_message,
notice->z_message_len));
/*
* Decide if its a control notice. If so, return the notice's
* opcode. Otherwise, return NULL:
*/
if ((strcasecmp(notice->z_class, WG_CTL_CLASS)==0) && /* <<<>>> */
(strcasecmp(notice->z_class_inst, WG_CTL_USER)==0))
return(notice->z_opcode);
return(0);
}