IBM Books

Group Services Programming Guide and Reference


The sample_utility.c utility functions

/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/*                                                                        */
/*                                                                        */
/* Licensed Materials - Property of IBM                                   */
/*                                                                        */
/* (C) COPYRIGHT International Business Machines Corp. 1996,2001          */
/* All Rights Reserved                                                    */
/*                                                                        */
/* US Government Users Restricted Rights - Use, duplication or            */
/* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.      */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
 
#if !defined(_HAGSD_COPYRIGHT_H)
#define _HAGSD_COPYRIGHT_H
static char copyright[] = "Licensed Materials - Property of IBM\n\
(C) COPYRIGHT International Business Machines Corp. 1996,2001.\n\
All Rights Reserved.\n\
US Government Users Restricted Rights - Use, duplication or \n\
disclosure restricted by GSA ADP Schedule Contract with IBM Corp.\n";
#endif
 
static char *sccsid = "@(#)95   1.30   src/rsct/pgs/samples/sample_utility.c, gssamples, rsct_r43x 5/14/01 09:43:19";
 
 
/*********************************************************************/
/*
 * Name:  sample_utility.c
 *
 * This program provides the set of utility functions used by the
 * "sample_test" and "sample_schg" programs.
 *
 * Components:
 *   sample_utility.c - this module, provides the definitions for the
 *      utility functions used by the sample_test and sample_schg
 *      programs.
 *
 *   sample_callbacks.c - provides the definitions for the callback
 *      functions used for the groups created by the sample_test
 *      program.
 *
 *   sample_test.c - contains the main() function for sample_test, which
 *      supports interaction with the user, and most calls to the Group
 *      Services interfaces.
 *
 *   sample_schg.c - contains the main() function for sample_schg, which
 *      contains the calls to Group Services interfaces, and also the
 *      callback functions used by sample_schg.
 *
 *   sample_callbacks.h - declarations for the callback functions
 *      contained in sample_callbacks.c.
 *
 *   sample_utility.h - declarations for the utility functions contained
 *      in sample_utility.c
 *
 * The information here assumes that you are familiar with the information
 * presented in the IBM PSSP Group Services Programming Guide and Reference
 * manual.
 *
 * This program is provided for illustrative purposes only, and is not
 * intended to be an authoritative description of the "best" methods to
 * use when writing a Group Services application.  It is intended to
 * demonstrate the various interfaces in a relatively verbose manner,
 * and to allow you to relatively easily manipulate groups and their
 * members.
 *
 * To this end, various aspects of this program (in particular its
 * handling of screen input and output) are neither robust nor
 * foolproof.  Therefore, you should take care when giving input to
 * this program.
 */
/*********************************************************************/
 
/*********************************************************************/
/*
 * Please refer to sample_test.c for information about building and
 * using the sample_test program.  Refer to sample_schg.c for such
 * information for the sample_schg program.
 *
 * Note that since this file is shared by sample_test and sample_schg,
 * all data and functions defined here are used only by sample_test.
 * Those sections NOT included via "#ifdef _SAMPLE_TEST/#endif" are
 * not used by sample_schg.
 */
/*********************************************************************/
 
/*********************************************************************/
/*
 * Utility functions.
 *
 * Ths utility functions handle pedestrian tasks such as formatting
 * and displaying the information contained in various notifications,
 * as well as querying the user for input data when creating protocol
 * proposals or asking for votes.
 *
 * These functions are used by the various callback functions in
 * sample_callbacks.c, as well as by the main() function contained in
 * sample_test.c.  The file sample_callbacks.h contains the prototypes
 * for the utility functions.
 */
/*********************************************************************/
 
/*********************************************************************/
/*
 * Include "standard" system files.  Note that pthread.h must be the
 * first file included, if it is to be included (see the standard AIX
 * documentation for more information about AIX thread support.)
 */
/*********************************************************************/
 
#ifdef _THREAD_SAFE                     /* begin _THREAD_SAFE */
#include <pthread.h>
#endif                                  /* end _THREAD_SAFE */
 
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <strings.h>
#include <memory.h>
#ifndef __linux__
#include <time.h>
#else
#include <sys/time.h>
#endif
#include <arpa/inet.h>
 
/*********************************************************************/
/*
 * Include the Group Services declarations file.
 */
/*********************************************************************/
 
#include <ha_gs.h>
 
/*********************************************************************/
/*
 * Include the set of declarations for utility functions for this program.
 */
/*********************************************************************/
 
#include "sample_utility.h"
 
#ifdef  _SAMPLE_TEST                    /* _SAMPLE_TEST */
/*********************************************************************/
/*
 * Include the set of declarations for callbacks for this program.
 */
/*********************************************************************/
 
#include "sample_callbacks.h"
#endif                                  /* ifdef _SAMPLE_TEST */
 
/**********************************************************************/
/*
 * These are "global" variables shared among the modules within the
 * sample_test program.
 */
 
int voting_phase;                       /* Which voting phase for the */
                                        /* current protocol? */
int handledResponsiveness = 0;          /* Received responsiveness notification? */
 
#ifdef  _SAMPLE_TEST                    /* _SAMPLE_TEST */
 
int verbose = 0;                        /* Verbose prompts? */
 
/*
 * Set up variables to hold the data pertaining to the groups which are
 * allowed for joining and subscribing.  We initializing the token arrays
 * to -1 to show that no token is yet in that slot (we assume that -1
 * will never represent a valid token, which is valid in AIX, as all tokens
 * will be in the range of 0-2048.)
 */
 
const int  num_groups = NUM_GROUPS;
const int  num_groups_for_subscribe = NUM_GROUPS_FOR_SUBSCRIBE;
const int  predef_groups_for_subscribe = NUM_GROUPS + 10;
 
#endif                                  /* ifdef _SAMPLE_TEST */
 
/* ha_gs_tokens_t for each group */
ha_gs_token_t  gid[] = {-1,-1,-1,-1,-1,-1,-1, -1, -1, -1};
 
/* provider id's for each group */
ha_gs_provider_t provId[NUM_GROUPS];        
 
 /* ha_gs_tokens_t for subscribing to each group */
ha_gs_token_t  sid[] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,\
                            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
 
/* subscription controls */
ha_gs_subscription_ctrl_t subCtrl[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
                                           0,0,0,0,0,0,0,0,0,0,0,0};
 
char   *subNames[NUM_GROUPS_FOR_SUBSCRIBE];
 
#ifdef  _SAMPLE_TEST                    /* _SAMPLE_TEST */
 
/*
 * The set of callback functions that are used for subscribing.  The
 * initial 8 entries are for subscribing to the pre-defined and user-
 * defined groups supported by sample_test for joining, the remaining
 * are used for subscriptions to other groups.
 */
ha_gs_subscription_cb_t *subCallbacks[] = {
    subscribe_cb0,
    subscribe_cb1,
    subscribe_cb2,
    subscribe_cb3,
    subscribe_cb4,
    subscribe_cb5,
    subscribe_cb6,
    subscribe_cb7,
    subscribe_cb_HostMbr,
    subscribe_cb_EnetMbr,
    subscribe_cb_CssMbr,
    subscribe_cb_TrMbr,
    subscribe_cb_FddiMbr,
    subscribe_cb_RS232Mbr,
    subscribe_cb_TmScsiMbr,
    subscribe_cb_SlipMbr,
    subscribe_cb_MyrinetMbr,
    subscribe_cb_Css1Mbr
    };
 
int     pickIdx = 99;
int     listIdx = 999;
ha_gs_subscription_cb_t        *pickCallback = subscribe_cb_Pick;
 
#endif                                  /* ifdef _SAMPLE_TEST */
 
/* flag for successful join of group */
int     in_group[] = {0,0,0,0,0,0,0,0,0,0}; 
 
 /* how many successes? */
int     in_group_count = 0;         
 
/* how many subscriptions? */
int     subscribed_to_count = 0;     
 
/* are we dealing with responsiveness interactively? */
int     interactiveInit = 0;
int     interactiveResponse = 0;
 
char *starz="**********++++++++++==========**********++++++++++==========\n";
char *asterisks="**********************************************************************\n";
 
/**********************************************************************/
/*
 * These variables provide the pre-defined names of groups, and portions
 * of the group attributes for these groups.
 */
 
#ifdef  _SAMPLE_TEST                    /* _SAMPLE_TEST */
 
/*
 * The names of the "pre-defined" groups for joining.
 */
char   *group_names[] = {
    "theSourceGroup",
    "OnePhaseJoin",
    "theTargetGroup",
    "theLonelyGroup",
    "ifFirstIWin",
    "SourceOrNot",
    "ChainGang",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    ""
};
 
/*
 * The names of the source-groups to be used by the respectives
 * groups listed in group_names[].
 */
char   *source_group_names[] = {
    "",
    "",
    "theSourceGroup",
    "theMissingGroup",
    "",
    "theSourceGroup",
    "theTargetGroup",
    "",
    "",
    "",
    ""
};
 
/*
 * The provider local names used for the join requests to the
 * respective groups listed in group_names[].
 */
char   *prov_local_names[] = {
    "SourceJoin",
    "SinglePhase",
    "Existing",
    "Missing",
    "AmIFirstOrALoser",
    "MaybeSourceIt",
    "DaisyChain",
    "NeverBeMe",
    "",
    "",
    ""
};
 
#endif                                  /* ifdef _SAMPLE_TEST */
 
/*
 * The base provider instance numbers used for the join requests
 * to the respective groups listed in group_names[].  The actual
 * instance number is built by adding the program's index number
 * to this base value.
 */
int     instance_numbers[] = {100, 200, 300, 400, 500, 600, 700, 800, 900, 1000};
 
/*
 * Array to hold the group attributes for the pre-defined groups.
 */
ha_gs_group_attributes_t *gattr[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 
/*********************************************************************/
/*
 * We will prepend all submitted state values and provider-broadcast
 * messages with a tag constructed from the program index, to ensure
 * that we don't truncate due to finding a null value there, and to
 * indicate which provider submitted the data.
 *
 * See sample_test.c for full details of how this "tag" is prepared,
 * these variables are used by the utility routines to construct the
 * values.
 */
 
int     sample_index = 1;               /* what is my index, for numbers, flags, etc? */
 
#ifdef  _SAMPLE_TEST                    /* _SAMPLE_TEST */
 
typedef struct {
    int st_pbm_index;
    char st_pbm_data[2500];
} st_pbm_struct;
 
char   *sample_prefix;                  /* prepend to msgs, states, etc. */
int     sample_prefix_len = 0;
 
char   *sample_pp = "<"; 
char   *sample_ee = ">";
 
 
/**********************************************************************/
 
/*
 * These arrays provide a rotating set of provider-broadcast messages,
 * proposed group state values, and updated default vote values, all of
 * which may be submitted along with vote values whenever the user needs
 * to vote on an n-phase protocol.
 *
 * The entry is chosen by taking the phase number for this protocol
 * modulo with the variable "NUMBER_MSG_ENTRIES", and using the result
 * as an index into these arrays.  An entry of '{0,0}' indicates that
 * no value will be submitted with this vote.
 */
 
ha_gs_provider_message_t	provider_msg_array[] = {
{ 35, "I am Born!  Or, is that, I am Borg?"},
{ 49, "Things do seem to be looking up now, do they not?"},
{ 36, "What a long, strange trip it's been!"},
{ 0, 0},
{ 252, "Fourscore and seven years ago, our fourfeathers brought into existence "\
       "that which cannot ever be compared to anything else, that which is to be, "\
       "umm, well, something.  Anyway, trust us.  It was quite a good plan they "\
       "had.  Plastics.  That's the ticket."},
{ 0, 0},
{ 124, "We come in peace.  All we want is a peace of what you got, and a peace "\
       "of what he's got, and a peace of what they've got..."},
{ 20, "Forest for the Cup!"}
};
 
ha_gs_state_value_t         state_value_array[] = {
{ 4, "1111"},
{ 0, 0},
{ 8, "22223333"},
{ 120, "hhhhhhhhppppppppppppLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL"\
       "LLLLLLLLxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"},
{ 0, 0},
{ 7, "7654321"},
{ 0, 0},
{ 13, "Forza azzuri"}
};
 
ha_gs_vote_value_t  default_vote_array[] = {
HA_GS_NULL_VOTE,
HA_GS_NULL_VOTE,
HA_GS_VOTE_APPROVE,
HA_GS_VOTE_REJECT,
HA_GS_NULL_VOTE,
HA_GS_NULL_VOTE,
HA_GS_NULL_VOTE,
HA_GS_VOTE_APPROVE
};
 
/*********************************************************************/
/*
 * Display the help information.
 */
char *instruct1="\nEnter: 'i'(ha_gs_init) '1'(1 phase join) 'j'(n phase join)\n";
char *instruct2=" 'x'(good target join, if 'j' was done) 'm'(bad target join)\n";
char *instruct3=" 'a'(mismatch attributes, if done by both even and odd indexed sample_tests)\n";
char *instruct4=" 't'(state value change) 'p'(provider broadcast message)\n";
char *instruct5=" 's'(subscribe to a group) 'u'(unsubscribe from a group)\n";
char *instruct6=" 'l'(leave a group) 'e'(expel one or more providers from a group)\n";
char *instruct7=" 'g'(even index: source 'theSourceGroup', odd index: no source-group)\n";
char *instruct8=" '3'(good target join, if 'j' and 'x' were done)\n";
char *instruct9=" 'b'(build a group by defining its attributes)\n";
char *instruct10=" 'n'(modify a group's attributes)\n";
char *instruct11=" 'y'(say goodbye (\"exit immediately from\") a group)\n";
char *instruct12=" 'z'(toggle HA_GS_DEACTIVATE_ON_FAILURE)\n";
char *instruct13=" 'w'(issue ha_gs_quit() but continue)\n";
char *instructL=" 'd'(ha_gs_dispatch) 'h' (print these instructions) 'q'(quit)\n";
char *instructv=" 'v'(ha_gs_get_adapter_info) 'h' (print these instructions) 'q' (quit)\n";
char *instructo=" 'o'(ha_gs_get_node_number) 'h' (print these instructions) 'q'(quit)\n";
 
void    write_instructions(int _verbose)
{
    printf(instruct1);
    printf(instruct2);
    printf(instruct3);
    printf(instruct4);
    printf(instruct5);
    printf(instruct6);
    printf(instruct7);
    printf(instruct8);
    printf(instruct9);
    printf(instruct10);
    printf(instruct11);
    printf(instruct12);
    printf(instruct13);
    printf(instructL);
    printf(instructo);
    printf(instructv);
    if (!_verbose) {
        printf("\nTo automatically get these instructions at each prompt, use\n");
        printf(" 'verbose' mode via '-v' on the command line.\n\n");
    }
    printf("To interactively specify initialization parameters, specify '-i' on\n");
    printf(" the command line.\n\n");
    fflush(stdout);
    return;
}
 
#endif                                  /* ifdef _SAMPLE_TEST */
 
/*********************************************************************/
/*
 * Calculate the current TOD, compare times, generate random numbers.
 */
char   *time_now( )
{
    struct timeval  current_time;
    struct timezone tz;
 
    gettimeofday(&current_time, &tz);
 
    return( ctime( (time_t *) &current_time.tv_sec ) );
}
 
time_t  time_since( struct timeval *event )
{
    time_t overdue;
    struct timeval  current_time;
    struct timezone tz;
 
    gettimeofday(&current_time, &tz);
 
    overdue = (time_t) ( current_time.tv_sec - event->tv_sec );
 
    return ( overdue );
}
 
void    write_the_time( )
{
    struct timeval  current_time;
    struct timezone tz;
    char            tod[32];            /* extract part of string. */
    char           *cTod;
 
    gettimeofday(&current_time, &tz);
 
                                        /* Grab month/day/time only. */
    cTod = ctime((time_t *) &current_time.tv_sec);
    memcpy(tod, cTod+4, 16);
    tod[15] = '\0';
 
    printf("\n[TOD(%s)]", tod);
 
    return;
}
 
float   randomp( )
{
    const unsigned long RANDMAX = 2147483648U; /* 2**31 */
                                              /* random() returns 0 to RANDMAX-1 */
 
    return( ((float) random()) / ((float) RANDMAX) );
}
 
long    randomn( unsigned long max )
{
    const unsigned long RANDMAX = 2147483648U; /* 2**31 */
                                              /* random() returns 0 to RANDMAX-1 */
    long rand;
 
    if ( 1 >= max ) return 0;
 
    if ( RANDMAX < max ) {
        rand = random();
        return 2*rand + rand%2;
    }
 
    while( (rand = random()) > max * ( RANDMAX/max ) );
 
    return( rand % max );
}
 
/**********************************************************************/
/*
 * These functions display various Group Services data types.  These are
 * used to display data from protocol submissions and notifications.
 */
 
/*
 * Display the type of protocol represented by a notification.
 */
char 	*proto_type(int req)
{
    switch(req) {
      case HA_GS_RESPONSIVENESS:
        return("HA_GS_RESPONSIVENESS");
      case HA_GS_JOIN:
        return("HA_GS_JOIN");
      case HA_GS_FAILURE_LEAVE:
        return("HA_GS_FAILURE_LEAVE");
      case HA_GS_LEAVE:
        return("HA_GS_LEAVE");
      case HA_GS_EXPEL:
        return("HA_GS_EXPEL");
      case HA_GS_STATE_VALUE_CHANGE:
        return("HA_GS_STATE_VALUE_CHANGE");
      case HA_GS_PROVIDER_MESSAGE:
        return("HA_GS_PROVIDER_MESSAGE");
      case HA_GS_CAST_OUT:
        return("HA_GS_CAST_OUT");
      case HA_GS_SOURCE_STATE_REFLECTION:
        return("HA_GS_SOURCE_STATE_REFLECTION");
      case HA_GS_MERGE:
        return("HA_GS_MERGE");
      case HA_GS_SUBSCRIPTION:
        return("HA_GS_SUBSCRIPTION");
      case HA_GS_GROUP_ATTRIBUTE_CHANGE:
        return("HA_GS_GROUP_ATTRIBUTE_CHANGE");
      default:
        printf("?? Unknown protocol request[%d] ??", req);
        return("Unknown");
    }
}
 
/*
 * Display the summary code contained in a notification.
 */
char	*sum_code(int sum)
{
    switch(sum) {
      case HA_GS_EXPLICIT_APPROVE:
        return("HA_GS_EXPLICIT_APPROVE");
      case HA_GS_EXPLICIT_REJECT:
        return("HA_GS_EXPLICIT_REJECT");
      case HA_GS_DEFAULT_APPROVE:
        return("HA_GS_DEFAULT_APPROVE");
      case HA_GS_DEFAULT_REJECT:
        return("HA_GS_DEFAULT_REJECT");
      case HA_GS_TIME_LIMIT_EXCEEDED:
        return("HA_GS_TIME_LIMIT_EXCEEDED");
      case HA_GS_PROVIDER_FAILED:
        return("HA_GS_PROVIDER_FAILED");
      case HA_GS_RESPONSIVENESS_NO_RESPONSE:
        return("HA_GS_RESPONSIVENESS_NO_RESPONSE");
      case HA_GS_RESPONSIVENESS_RESPONSE:
        return("HA_GS_RESPONSIVENESS_RESPONSE");
      case HA_GS_GROUP_DISSOLVED:
        return("HA_GS_GROUP_DISSOLVED");
      case HA_GS_GROUP_SERVICES_HAS_DIED_HORRIBLY:
        return("HA_GS_GROUP_SERVICES_HAS_DIED_HORRIBLY");
      case HA_GS_DEACTIVATE_UNSUCCESSFUL:
        return("HA_GS_DEACTIVATE_UNSUCCESSFUL");
      case HA_GS_DEACTIVATE_TIME_LIMIT_EXCEEDED:
        return("HA_GS_DEACTIVATE_TIME_LIMIT_EXCEEDED");
      default:
        printf("?? Unknown summary code[%d] ??", sum);
        return("Unknown");
    }
}
 
/*
 * Display the number of phases for a given protocol.
 */
char    *phase_print(int phase)
{
    switch(phase) {
      case HA_GS_1_PHASE:
        return("1_PHASE");
      case HA_GS_N_PHASE:
        return("N_PHASE");
      default:
        printf("?? Unknown phase specification[%d] ??", phase);
        return("Unknown");
    }
}
 
/*
 * Display the batching control group attribute.
 */
char    *batch_print(int batch)
{
    static char msg[100];
    if(batch & HA_GS_DEACTIVATE_ON_FAILURE) {
	strcpy(msg, "HA_GS_DEACTIVATE_ON_FAILURE|");
    } else {
    	strcpy(msg,"");
    }
 
    switch( (batch & ~(HA_GS_DEACTIVATE_ON_FAILURE))) {
      case HA_GS_NO_BATCHING:
		strcat(msg, "HA_GS_NO_BATCHING");
		return msg;
      case HA_GS_BATCH_JOINS:
      		strcat(msg, "HA_GS_BATCH_JOINS");
		return msg;
      case HA_GS_BATCH_LEAVES:
		strcat(msg,"HA_GS_BATCH_LEAVES");
		return msg;
 
      case HA_GS_BATCH_BOTH:
		strcat(msg, "HA_GS_BATCH_BOTH");
		return msg;
      default:
        printf("?? Unknown batch control[%d] ??", batch);
        return("Unknown");
    } 
}
 
/*
 * Display the merge control group attribute.
 */
char    *merge_print(int merge)
{
    switch(merge) {
      case HA_GS_DISSOLVE_MERGE:
        return("HA_GS_DISSOLVE_MERGE");
      case HA_GS_LARGER_MERGE:
        return("HA_GS_LARGER_MERGE");
      case HA_GS_SMALLER_MERGE:
        return("HA_GS_SMALLER_MERGE");
      case HA_GS_DONTCARE_MERGE:
        return("HA_GS_DONTCARE_MERGE");
      default:
        printf("?? Unknown merge control[%d] ??", merge);
        return("Unknown");
    }
}
 
/*
 * Display the type of responsiveness specified.
 */
char    *responsive_print(int resp)
{
    switch(resp) {
      case HA_GS_NO_RESPONSIVENESS:
        return("HA_GS_NO_RESPONSIVENESS");
      case HA_GS_PING_RESPONSIVENESS:
        return("HA_GS_PING_RESPONSIVENESS");
      case HA_GS_COUNTER_RESPONSIVENESS:
        return("HA_GS_COUNTER_RESPONSIVENESS");
      default:
        printf("?? Unknown responsiveness type [%d] ??", resp);
        return("Unknown");
    }
}
 
/*
 * Display the contents of the whats changed field from a notification.
 */
char    *what_changed(int what)
{
    switch(what) {
      case HA_GS_NO_CHANGE:
        return("HA_GS_NO_CHANGE");
      case HA_GS_PROPOSED_MEMBERSHIP:
        return("HA_GS_PROPOSED_MEMBERSHIP");
      case HA_GS_ONGOING_MEMBERSHIP:
        return("HA_GS_ONGOING_MEMBERSHIP");
      case HA_GS_PROPOSED_STATE_VALUE:
        return("HA_GS_PROPOSED_STATE_VALUE");
      case HA_GS_ONGOING_STATE_VALUE:
        return("HA_GS_ONGOING_STATE_VALUE");
      case HA_GS_UPDATED_PROVIDER_MESSAGE:
        return("HA_GS_UPDATED_PROVIDER_MESSAGE");
      case HA_GS_UPDATED_MEMBERSHIP:
        return("HA_GS_UPDATED_MEMBERSHIP");
      case HA_GS_REJECTED_MEMBERSHIP:
        return("HA_GS_REJECTED_MEMBERSHIP");
      case HA_GS_UPDATED_STATE_VALUE:
        return("HA_GS_UPDATED_STATE_VALUE");
      case HA_GS_REFLECTED_SOURCE_STATE_VALUE:
        return("HA_GS_REFLECTED_SOURCE_STATE_VALUE");
      case HA_GS_EXPEL_INFORMATION:
        return("HA_GS_EXPEL_INFORMATION");
      case HA_GS_PROPOSED_GROUP_ATTRIBUTES:
        return("HA_GS_PROPOSED_GROUP_ATTRIBUTES");
      case HA_GS_ONGOING_GROUP_ATTRIBUTES:
        return("HA_GS_ONGOING_GROUP_ATTRIBUTES");
      case HA_GS_UPDATED_GROUP_ATTRIBUTES:
        return("HA_GS_UPDATED_GROUP_ATTRIBUTES");
      case HA_GS_REJECTED_GROUP_ATTRIBUTES:
        return("HA_GS_REJECTED_GROUP_ATTRIBUTES");
      default:
        printf("?? Unknown what's changed control[%d] ??", what);
        return("Unknown");
    }
}
 
/*
 * Display the subscription control flag.
 */
char    *write_sub_ctrl(ha_gs_subscription_ctrl_t subCtrl)
{
    switch(subCtrl) {
      case 0:
        return("No subscriptions!");
      case HA_GS_SUBSCRIBE_STATE:
        return("HA_GS_SUBSCRIBE_STATE");
      case HA_GS_SUBSCRIBE_DELTA_JOINS:
        return("HA_GS_SUBSCRIBE_DELTA_JOINS");
      case HA_GS_SUBSCRIBE_DELTA_LEAVES:
        return("HA_GS_SUBSCRIBE_DELTA_LEAVES");
      case HA_GS_SUBSCRIBE_DELTAS_ONLY:
        return("HA_GS_SUBSCRIBE_DELTAS_ONLY");
      case HA_GS_SUBSCRIBE_MEMBERSHIP:
        return("HA_GS_SUBSCRIBE_MEMBERSHIP");
      case HA_GS_SUBSCRIBE_ALL_MEMBERSHIP:
        return("HA_GS_SUBSCRIBE_ALL_MEMBERSHIP");
      case HA_GS_SUBSCRIBE_STATE_AND_MEMBERSHIP:
        return("HA_GS_SUBSCRIBE_STATE_AND_MEMBERSHIP");
      default:
        printf("?? Unknown subscription control[%d] ??", subCtrl);
        return("Unknown");
    }
}
 
/*
 * Display the type of a specified subscription request.
 */
void    write_sub_type(ha_gs_subscription_type_t subType)
{
    int foo;
    foo = 0;
 
    printf("Subscription data[");
    if (HA_GS_SUBSCRIPTION_STATE & subType) {
        printf("HA_GS_SUBSCRIPTION_STATE");
        foo++;
    }
    if (HA_GS_SUBSCRIPTION_DELTA_JOIN & subType) {
        if (foo) {
            printf("\n                  ");
            foo = 0;
        }
        printf("HA_GS_SUBSCRIPTION_DELTA_JOIN");
        foo++;
    }
    if (HA_GS_SUBSCRIPTION_DELTA_LEAVE & subType) {
        if (foo) {
            printf("\n                  ");
            foo = 0;
        }
        printf("HA_GS_SUBSCRIPTION_DELTA_LEAVE");
        foo++;
    }
    if (HA_GS_SUBSCRIPTION_MEMBERSHIP & subType) {
        if (foo) {
            printf("\n                  ");
            foo = 0;
        }
        printf("HA_GS_SUBSCRIPTION_MEMBERSHIP");
        foo++;
    }
    if (HA_GS_SUBSCRIPTION_DISSOLVED & subType) {
        if (foo) {
            printf("\n                  ");
            foo = 0;
        }
        printf("HA_GS_SUBSCRIPTION_DISSOLVED");
        foo++;
    }
    if (HA_GS_SUBSCRIPTION_GS_HAS_DIED & subType) {
        if (foo) {
            printf("\n                  ");
            foo = 0;
        }
        printf("HA_GS_SUBSCRIPTION_GS_HAS_DIED");
    }
    printf("]\n");
    fflush(stdout);
}
 
/*
 * Display the "name" of a Group Services return code.
 */
char    *write_an_rc(ha_gs_rc_t pRC)
{
    switch(pRC) {
      case HA_GS_OK:
        return("HA_GS_OK");
      case HA_GS_NOT_OK:
        return("HA_GS_NOT_OK");
      case HA_GS_EXISTS:
        return("HA_GS_EXISTS");
      case HA_GS_NO_INIT:
        return("HA_GS_NO_INIT");
      case HA_GS_NAME_TOO_LONG:
        return("HA_GS_NAME_TOO_LONG");
      case HA_GS_NO_MEMORY:
        return("HA_GS_NO_MEMORY");
      case HA_GS_NOT_A_MEMBER:
        return("HA_GS_NOT_A_MEMBER");
      case HA_GS_BAD_CLIENT_TOKEN:
        return("HA_GS_BAD_CLIENT_TOKEN");
      case HA_GS_BAD_MEMBER_TOKEN:
        return("HA_GS_BAD_MEMBER_TOKEN");
      case HA_GS_BAD_PARAMETER:
        return("HA_GS_BAD_PARAMETER");
      case HA_GS_UNKNOWN_GROUP:
        return("HA_GS_UNKNOWN_GROUP");
      case HA_GS_INVALID_GROUP:
        return("HA_GS_INVALID_GROUP");
      case HA_GS_NO_SOURCE_GROUP_PROVIDER:
        return("HA_GS_NO_SOURCE_GROUP_PROVIDER");
      case HA_GS_BAD_GROUP_ATTRIBUTES:
        return("HA_GS_BAD_GROUP_ATTRIBUTES");
      case HA_GS_WRONG_OLD_STATE:
        return("HA_GS_WRONG_OLD_STATE");
      case HA_GS_DUPLICATE_INSTANCE_NUMBER:
        return("HA_GS_DUPLICATE_INSTANCE_NUMBER");
      case HA_GS_COLLIDE:
        return("HA_GS_COLLIDE");
      case HA_GS_SOCK_CREATE_FAILED:
        return("HA_GS_SOCK_CREATE_FAILED");
      case HA_GS_SOCK_INIT_FAILED:
        return("HA_GS_SOCK_INIT_FAILED");
      case HA_GS_CONNECT_FAILED:
        return("HA_GS_CONNECT_FAILED");
      case HA_GS_VOTE_NOT_EXPECTED:
        return("HA_GS_VOTE_NOT_EXPECTED");
      case HA_GS_NOT_SUPPORTED:
        return("HA_GS_NOT_SUPPORTED");
      case HA_GS_INVALID_SOURCE_GROUP:
        return("HA_GS_INVALID_SOURCE_GROUP");
      case HA_GS_UNKNOWN_PROVIDER:
        return("HA_GS_UNKNOWN_PROVIDER");
      case HA_GS_INVALID_DEACTIVATE_PHASE:
        return("HA_GS_INVALID_DEACTIVATE_PHASE");
      case HA_GS_PROVIDER_APPEARS_TWICE:
        return("HA_GS_PROVIDER_APPEARS_TWICE");
      case HA_GS_BACKLEVEL_PROVIDERS:
        return("HA_GS_BACKLEVEL_PROVIDERS");
      case HA_GS_NULL_ADAPTER_INFO:
        return("HA_GS_NULL_ADAPTER_INFO");
      case HA_GS_ADAPTER_INFO_NOT_FOUND:
        return("HA_GS_ADAPTER_INFO_NOT_FOUND");
      case HA_GS_ADAPTER_INFO_NOT_SENT:
        return("HA_GS_ADAPTER_INFO_NOT_SENT");
      default:
        printf("?? Unknown return code[%d] ??", pRC);
        return("Unknown");
    }
}
 
/*
 * Display the value of the given vote value.
 */
char    *write_a_vote(ha_gs_vote_value_t vote)
{
    switch(vote) {
      case HA_GS_NULL_VOTE:
        return("HA_GS_NULL_VOTE");
      case HA_GS_VOTE_APPROVE:
        return("HA_GS_VOTE_APPROVE");
      case HA_GS_VOTE_CONTINUE:
        return("HA_GS_VOTE_CONTINUE");
      case HA_GS_VOTE_REJECT:
        return("HA_GS_VOTE_REJECT");
      default:
        printf("?? Unknown vote value[%d] ??", vote);
        return("Unknown");
    }
}
 
/*
 * Display the leave reason as given in a notification.
 */
char   *write_leave_reason(ha_gs_leave_reasons_t why)
{
    switch(why) {
      case HA_GS_VOLUNTARY_LEAVE:
        return("HA_GS_VOLUNTARY_LEAVE");
        break;
      case HA_GS_PROVIDER_FAILURE:
        return("HA_GS_PROVIDER_FAILURE");
        break;
      case HA_GS_HOST_FAILURE:
        return("HA_GS_HOST_FAILURE");
        break;
      case HA_GS_PROVIDER_EXPELLED:
        return("HA_GS_PROVIDER_EXPELLED");
        break;
      case HA_GS_SOURCE_PROVIDER_LEAVE:
        return("HA_GS_SOURCE_PROVIDER_LEAVE");
        break;
      case HA_GS_PROVIDER_SAID_GOODBYE:
        return("HA_GS_PROVIDER_SAID_GOODBYE");
        break;        
      default:
        printf("Unknown leave code[%d]!", why);
        break;
    }
 
    return("Unknown");
}
 
/*
 * Display the group attributes.
 */
void    write_the_attributes(ha_gs_group_attributes_t *gAttrs)
{
    printf("Group attributes: \n");
    printf(" version[%d] size[%d] client version[%d]\n",
           gAttrs->gs_version,
           gAttrs->gs_sizeof_group_attributes,
           gAttrs->gs_client_version);
    printf(" Batching[%s] Join/Fail phases[%s] Reflection phases[%s]\n",
           batch_print(gAttrs->gs_batch_control),
           phase_print(gAttrs->gs_num_phases),
           phase_print(gAttrs->gs_source_reflection_num_phases));
    printf(" Default vote[%s] Merge[%s]\n",
           write_a_vote(gAttrs->gs_group_default_vote),
           merge_print(gAttrs->gs_merge_control));
    printf(" Time limits: join/fail[%d] reflection[%d]\n",
           gAttrs->gs_time_limit,
           gAttrs->gs_source_reflection_time_limit);
    printf(" Group name[%s]", gAttrs->gs_group_name);
    if (gAttrs->gs_source_group_name) {
        printf(" Source group name[%s]", gAttrs->gs_source_group_name);
    }
    printf("\n");
    fflush(stdout);
    return;
}       
 
#ifdef  _SAMPLE_TEST                    /* _SAMPLE_TEST */
/*
 * Copy a set of group attributes to save them.
 */
void    copy_the_attributes(int groupIdx,
                            ha_gs_group_attributes_t *gAttrsTarg,
                            ha_gs_group_attributes_t *gAttrsSrc)
{
 
    ha_gs_copy_group_attributes(gAttrsTarg, gAttrsSrc);
    gattr[groupIdx] = gAttrsTarg;
 
    /*
     * The names in the new attributes better match what we have cached!
     */
    if (0 != strcmp(gAttrsTarg->gs_group_name, group_names[groupIdx])) {
        printf("Error: New attributes have group name [%s], old have [%s]!\n",
               gAttrsSrc->gs_group_name,
               group_names[groupIdx]);
    }
    if (0 != strcmp(gAttrsTarg->gs_source_group_name, source_group_names[groupIdx])) {
        printf("Error: New attributes have source group name [%s], old have [%s]!\n",
               gAttrsSrc->gs_source_group_name,
               source_group_names[groupIdx]);
    }
 
    return;
}
#endif                                  /* ifdef _SAMPLE_TEST */
 
/*
 * Display the information to be submitted for a join (via ha_gs_join()),
 * any of the various group join commands.
 */
void    write_join_information(int gIndex)
{
    ha_gs_group_attributes_t *gAttrs;
    int inst_num;
 
    printf(starz);
    if (0 == (gAttrs = gattr[gIndex])) {
        printf("No group attributes established for index [%d]!  Leaving.\n",
               gIndex);
        printf(starz);
        return;
    }
 
    printf("Attempting JOIN for group[%s]:\n",
           gAttrs->gs_group_name);
    inst_num = instance_numbers[gIndex];
#ifdef  _SAMPLE_TEST                    /* _SAMPLE_TEST */
    printf(" My instance #[%d]  local name[%s]\n",
           inst_num,
           prov_local_names[gIndex]);
#else                                  /* else ifdef _SAMPLE_TEST */
    printf(" My instance #[%d]\n",
           inst_num);
#endif                                  /* ifdef _SAMPLE_TEST */
    write_the_attributes(gAttrs);
 
    printf(starz);
    fflush(stdout);
    return;
}
 
/*
 * Display a vote value.
 */
void    write_the_vote(ha_gs_vote_value_t vote)
{
    printf("vote value[%s]", write_a_vote(vote));
 
    return;
}
 
/**********************************************************************/
/*
 * Display the information contained in various notifications.
 */
 
/*
 * Display an arbitrary group state value or provider message.  For
 * those non-predefined groups, we do not know the format of the group's
 * state value, or any provider messages.  Also, certain other routines
 * may not know which group.  At these times, we use this routine to
 * display these values in a (somewhat) intelligent format.
 *
 * We first display as characters, representing non-printable characters
 * as periods ('.').  We then do either or both of the following:
 * - if the length is equivalent to one or more integers, display each
 *    word as its integral value.
 * - display the whole value as a raw hex stream.
 */
void    write_arbitrary_value(int   which,
                              void *value)
{
    char *_val, *_val2;
    int   _len, _len2, _cnt, _isize, _stpbmint;
    char *_buffer;
    char *_bufPtr;
 
    ha_gs_state_value_t      *_state;
    ha_gs_provider_message_t *_pbm;
 
    if (ARBITRARY_STATE_VALUE == which) {
        _state = (ha_gs_state_value_t *)value;
        _len = _state->gs_length;
        _val = _state->gs_state;
        printf("state value[");
    } else {
        _pbm = (ha_gs_provider_message_t *)value;
        _len = _pbm->gs_length;
        _val = _pbm->gs_message;
        printf("provider message[");
    }
    
    if (0 >= _len) {
 
        /* Nothing here. */
 
        printf("]\n");
        fflush(stdout);
        return;
    }
 
    _buffer = (char *)malloc((_len * 5) + 1); /* Buffer in which to build string. */
 
    /*
     * Display assuming it is actually printable.
     */
    for (_len2 = _len, _val2 = _val, _bufPtr = _buffer;
         0 < _len2;
         ) {
 
        for (_cnt = 0;
             ((4 > _cnt) && (0 < _len2));
             _cnt++, _len2--) {
 
            if (isprint(*_val2)) {
                sprintf(_bufPtr++, "%c", *_val2++);
            } else {
                *_bufPtr++ = '.';
                _val2++;
            }
        }
    }
 
    *_bufPtr++ = '\0';
 
    printf("[%s]\n",_buffer);
    fflush(stdout);
 
    /*
     * If integral number of words, display as series of ints.
     */
    _isize = sizeof(_stpbmint);
    if (0 == (_len % _isize)) {
        printf("[");
        if (_isize == _len) {
            /* assume an int */
            memcpy(&_stpbmint, _val, sizeof(_stpbmint));
            printf("%d", _stpbmint);
        } else {
            /* assume series of ints */
            for (_len2 = 0, _val2 = _val;
                 _len2 < _len;
                 _len2 += 4, _val2 += 4) {
                memcpy(&_stpbmint, _val2, sizeof(_stpbmint));
                printf("%d", _stpbmint);
                if (_len2 != (_len - 4)) {
                    printf(" ");
                }
            }
        }
        printf("]\n");
        fflush(stdout);
    }
 
    /*
     * Now, convert to "printable" hex.
     */
    for (_len2 = _len, _val2 = _val, _bufPtr = _buffer;
         0 < _len2;
         ) {
 
        sprintf(_bufPtr, "0x");
        _bufPtr += 2;
 
        for (_cnt = 0;
             ((4 > _cnt) && (0 < _len2));
             _cnt++, _len2--) {
 
            sprintf(_bufPtr, "%02x", *_val2++);
            _bufPtr += 2;
        }
 
        *_bufPtr++ = ' ';
    }
 
    *_bufPtr++ = '\0';
 
    printf("[%s]]\n",_buffer);
    fflush(stdout);
 
    free(_buffer);
 
    return;
}
 
/*
 * Display a notification received from Group Services.
 */
void    write_the_notification(int groupIdx,
                               void * addr,
                               ha_gs_notification_type_t whatItBe)
{
    unsigned int        i, j, mask, whatchanged, which_msg;
    int                 stpbmint, full_proposal, grabbedIt, iHaveLeft;
    int                 expelledMyself, iBeenExpelled;
    char               *ctr;
 
    ha_gs_proposal_t       *proposal;
    ha_gs_responsiveness_t *response;
 
    ha_gs_request_t         pType;
    ha_gs_provider_t        pProposer;
    ha_gs_token_t           pToken;
 
    ha_gs_membership_t     *membership;
    ha_gs_provider_t       *provider;
 
    ha_gs_summary_code_t    summary_code;
 
    ha_gs_state_value_t    *state;
    ha_gs_provider_message_t *pbm;
 
    ha_gs_n_phase_notification_t  *note;
    ha_gs_approved_notification_t *appr;
    ha_gs_rejected_notification_t *rej;
    ha_gs_announcement_notification_t *announce;
    ha_gs_responsiveness_notification_t *resp;
 
    ha_gs_leave_array_t *leave_array;
    ha_gs_leave_info_t  *leave_info;
    ha_gs_expel_info_t  *expel_info;
 
    note = (ha_gs_n_phase_notification_t *)addr;
    appr = (ha_gs_approved_notification_t *)addr;
    rej = (ha_gs_rejected_notification_t *)addr;
    announce = (ha_gs_announcement_notification_t *)addr;
    resp = (ha_gs_responsiveness_notification_t *)addr;
 
    printf("%.21s  %.24s  %.21s\n", asterisks, time_now(), asterisks);
 
    full_proposal = 1;
    grabbedIt = 0;
    iHaveLeft = 0;
    iBeenExpelled = 0;
    expelledMyself = 0;
 
    switch(whatItBe) {
      case HA_GS_N_PHASE_NOTIFICATION:
        pType = note->gs_protocol_type;
        pToken = note->gs_provider_token;
        printf("Type[%s] Token[%d] TimeLimit[%d]\n",
               proto_type(pType),
               pToken,
               note->gs_time_limit);
 
        proposal = note->gs_proposal;
        pProposer = proposal->gs_proposed_by;
        summary_code = note->gs_summary_code;
        membership = proposal->gs_current_providers;
        break;
      case HA_GS_APPROVED_NOTIFICATION:
        pType = appr->gs_protocol_type;
        pToken = appr->gs_provider_token;
        printf("Type[%s] Token[%d]\n",
               proto_type(pType),
               pToken);
 
        proposal = appr->gs_proposal;
        pProposer = proposal->gs_proposed_by;
        summary_code = appr->gs_summary_code;
        membership = proposal->gs_current_providers;
        break;
      case HA_GS_REJECTED_NOTIFICATION:
        pType = rej->gs_protocol_type;
        pToken = rej->gs_provider_token;
        printf("Type[%s] Token[%d]\n",
               proto_type(pType),
               pToken);
 
        proposal = rej->gs_proposal;
        pProposer = proposal->gs_proposed_by;
        summary_code = rej->gs_summary_code;
        membership = proposal->gs_current_providers;
        break;
      case HA_GS_ANNOUNCEMENT_NOTIFICATION:
        printf("Type[HA_GS_ANNOUNCEMENT_NOTIFICATION] Token[%d]\n",
               announce->gs_provider_token);
 
        summary_code = announce->gs_summary_code;
        membership = announce->gs_announcement;
        full_proposal = 0;
        break;
 
      case HA_GS_RESPONSIVENESS_NOTIFICATION:
 
        response = &(resp->gs_responsiveness_information);
 
        printf("Type[HA_GS_RESPONSIVENESS_NOTIFICATION] Type[%s]\n",
               responsive_print(response->gs_responsiveness_type));
 
        printf("Interval[%d seconds] Response time limit[%d seconds]\n",
               response->gs_responsiveness_interval,
               response->gs_responsiveness_response_time_limit);
 
        if (HA_GS_COUNTER_RESPONSIVENESS == response->gs_responsiveness_type) {
            printf(" Counter location[%x] Counter length[%d] Current value[\n",
                   response->gs_counter_location,
                   response->gs_counter_length);
            ctr = (char *)response->gs_counter_location;
            for (i = 0;
                 i < response->gs_counter_length;
                 i++, ctr++) {
                printf("%1.1x", 
                       (void *)ctr);
            }
            printf("]\n");
        }
 
        printf(asterisks);
        fflush(stdout);
        return;
 
      default:
        printf("Unknown protocol notification type: %d\n", whatItBe);
        fflush(stdout);
        return;
    }
    fflush(stdout);
 
    printf("Summary_Code[");
    mask = HA_GS_MIN_SUMMARY_CODE;
    for(i=1, j=0; mask <= HA_GS_MAX_SUMMARY_CODE; i++,mask <<= 1) {
	if (summary_code & mask) {
            if (2 == j) {
                printf("\n             ");
                j = 0;
            } else if (1 == j) {
                printf(" ");
            }
            printf("%s",sum_code(mask));
            j++;
        }
	else continue;
    }
    printf("]\n");
    fflush(stdout);
 
    if (full_proposal) {
#ifndef _VERBOSE_PROVIDER_OUTPUT
        printf("NumPhases[%s] ThisPhase[%d] Proposer[%d/%d]\n",
               phase_print(proposal->gs_phase_info.gs_num_phases),
               proposal->gs_phase_info.gs_phase_number,
               proposal->gs_proposed_by.gs_instance_number,
               proposal->gs_proposed_by.gs_node_number);
#else
        /* do not print out the int value. */
        printf("NumPhases[%s] ThisPhase[%d] Proposer[%d/%d(%d)]\n",
               phase_print(proposal->gs_phase_info.gs_num_phases),
               proposal->gs_phase_info.gs_phase_number,
               proposal->gs_proposed_by.gs_instance_number,
               proposal->gs_proposed_by.gs_node_number,
               proposal->gs_proposed_by.gs_provider_id);
#endif  /* if ! _VERBOSE_PROVIDER_OUTPUT */
        printf("WhatsChanged[");
        if (proposal->gs_whats_changed == HA_GS_NO_CHANGE) {
            printf("%s", what_changed(HA_GS_NO_CHANGE));
        } else {
            j = 0;
            for (i=0;i<31;i++) {
                if (proposal->gs_whats_changed & (1<<i)) {
                    if (2 == j) {
                        printf("\n             ");
                        j = 0;
                    } else if (1 == j) {
                        printf(" ");
                    }
                    printf("%s", what_changed(1<<i));
                    j++;
                }
            }
        }
        printf("]\n");
        fflush(stdout);
    }
 
    if (NULL != membership) {
        if (full_proposal) {
            printf("CurrentProviders[");
        } else {
            printf("AffectedProviders[");
        }
        if (membership->gs_count == 0) {
            printf("No providers in list!");
        } else {
            printf("count[%d] Members[", membership->gs_count);
            provider = membership->gs_providers;
            for (i = 0; i < membership->gs_count; i++) {
#ifndef _VERBOSE_PROVIDER_OUTPUT
                printf("%d/%d ",
                       provider->gs_instance_number,
                       provider->gs_node_number);
#else
                /* do not print out the int value. */
                printf("%d/%d(%d) ",
                       provider->gs_instance_number,
                       provider->gs_node_number,
                       provider->gs_provider_id);
#endif  /* if ! _VERBOSE_PROVIDER_OUTPUT */
                provider++;
            }
            printf("]");
        }
        printf("]\n");
        fflush(stdout);
    }
 
    if (!full_proposal) {
        printf(asterisks);
        fflush(stdout);
        return;
    }
 
    whatchanged = proposal->gs_whats_changed;
 
    if ((HA_GS_PROPOSED_MEMBERSHIP & whatchanged) ||
        (HA_GS_ONGOING_MEMBERSHIP & whatchanged) ||
        (HA_GS_UPDATED_MEMBERSHIP & whatchanged) ||
        (HA_GS_REJECTED_MEMBERSHIP & whatchanged)) {
        membership = proposal->gs_changing_providers;
        printf("ChangingProviders[");
        if (membership->gs_count == 0) {
            printf("No changing providers!");
        } else {
            printf("count[%d] Members[", membership->gs_count);
            provider = membership->gs_providers;
            for (i = 0; i < membership->gs_count; i++) {
 
                /* If this is a join, then the "proposer" id will always be us. */
                /* If we are in the changing providers list, this is "our" join, */
                /* so grab the provider id. */
                if ((HA_GS_JOIN == pType) &&
                    (HA_GS_APPROVED_NOTIFICATION == whatItBe) &&
                    (provider->gs_provider_id == pProposer.gs_provider_id)) {
                    
                    provId[groupIdx] = pProposer;
                    grabbedIt = 1;
                }
 
                /* If this is a "voluntary" leave, then maybe it is us that is */
                /* leaving.  In this case, the proposer should be us, and the changing */
                /* provider list better also be us.  Note that if we are the provider */
                /* leaving, then this will be the only notification we will get! */
                if (HA_GS_LEAVE == pType) {
                    if (provId[groupIdx].gs_provider_id == pProposer.gs_provider_id) {
                        iHaveLeft = 1;
                    }
                    if (provider->gs_provider_id != pProposer.gs_provider_id) {
#ifndef _VERBOSE_PROVIDER_OUTPUT
                        printf("\nError: proposer is [%d/%d] but changer is:",
                               pProposer.gs_instance_number,
                               pProposer.gs_node_number);
#else
                        /* do not print out the int value. */
                        printf("\nError: proposer is [%d/%d(%d)] but changer is:",
                               pProposer.gs_instance_number,
                               pProposer.gs_node_number,
                               pProposer.gs_provider_id);
#endif  /* if ! _VERBOSE_PROVIDER_OUTPUT */
                    }
                }
 
                /* If *WE* have just been the target of an expel, and that expel */
                /* was approved, bad news!  We have been tossed from the group! */
                if ((HA_GS_EXPEL == pType) &&
                    (provId[groupIdx].gs_provider_id == provider->gs_provider_id)) {
                    iBeenExpelled = 1;
                    if (provider->gs_provider_id == pProposer.gs_provider_id) {
                        expelledMyself = 1;
                    }
                }
#ifndef _VERBOSE_PROVIDER_OUTPUT
                printf("%d/%d ",
                       provider->gs_instance_number,
                       provider->gs_node_number);
#else
                /* do not print out the int value. */
                printf("%d/%d(%d) ",
                       provider->gs_instance_number,
                       provider->gs_node_number,
                       provider->gs_provider_id);
#endif  /* if ! _VERBOSE_PROVIDER_OUTPUT */
                provider++;
            }
            printf("]");
        }
        printf("]\n");
 
        if (grabbedIt) {
#ifndef _VERBOSE_PROVIDER_OUTPUT
            printf(">>>> Grabbed my provider id [%d/%d]\n",
                   provId[groupIdx].gs_instance_number,
                   provId[groupIdx].gs_node_number);
#else
            /* do not print out the int value. */
            printf(">>>> Grabbed my provider id [%d/%d(%d)]\n",
                   provId[groupIdx].gs_instance_number,
                   provId[groupIdx].gs_node_number,
                   provId[groupIdx].gs_provider_id);
#endif  /* if ! _VERBOSE_PROVIDER_OUTPUT */
        }
        if (iHaveLeft) {
#ifndef _VERBOSE_PROVIDER_OUTPUT
            printf(">>>> I have left the group, provider id was [%d/%d]\n",
                   provId[groupIdx].gs_instance_number,
                   provId[groupIdx].gs_node_number);
#else
            /* do not print out the int value. */
            printf(">>>> I have left the group, provider id was [%d/%d(%d)]\n",
                   provId[groupIdx].gs_instance_number,
                   provId[groupIdx].gs_node_number,
                   provId[groupIdx].gs_provider_id);
#endif  /* if ! _VERBOSE_PROVIDER_OUTPUT */
            provId[groupIdx].gs_provider_id = -1;
            in_group[groupIdx] = 0;
            in_group_count--;
        }
        if (iBeenExpelled) {
            if (HA_GS_APPROVED_NOTIFICATION == whatItBe) {
                if (expelledMyself) {
#ifndef _VERBOSE_PROVIDER_OUTPUT
                    printf(">>>> I've expelled myself [%d/%d] from the group!  Ouch!\n",
                           provId[groupIdx].gs_instance_number,
                           provId[groupIdx].gs_node_number);
#else
                    /* do not print out the int value. */
                    printf(">>>> I've expelled myself [%d/%d(%d)] from the group!  Ouch!\n",
                           provId[groupIdx].gs_instance_number,
                           provId[groupIdx].gs_node_number,
                           provId[groupIdx].gs_provider_id);
#endif  /* if ! _VERBOSE_PROVIDER_OUTPUT */
                } else {
#ifndef _VERBOSE_PROVIDER_OUTPUT
                    printf(">>>> They've expelled me [%d/%d] from the group!  The rats!\n",
                           provId[groupIdx].gs_instance_number,
                           provId[groupIdx].gs_node_number);
#else
                    /* do not print out the int value. */
                    printf(">>>> They've expelled me [%d/%d(%d)] from the group!  The rats!\n",
                           provId[groupIdx].gs_instance_number,
                           provId[groupIdx].gs_node_number,
                           provId[groupIdx].gs_provider_id);
#endif  /* if ! _VERBOSE_PROVIDER_OUTPUT */
                }
                provId[groupIdx].gs_provider_id = -1;
                in_group[groupIdx] = 0;
                in_group_count--;
            } else if (HA_GS_REJECTED_NOTIFICATION == whatItBe) {
                if (expelledMyself) {
#ifndef _VERBOSE_PROVIDER_OUTPUT
                    printf("I failed to expel myself [%d/%d].  Strange, but true!\n",
                           provId[groupIdx].gs_instance_number,
                           provId[groupIdx].gs_node_number);
#else
                    /* do not print out the int value. */
                    printf("I failed to expel myself [%d/%d(%d)].  Strange, but true!\n",
                           provId[groupIdx].gs_instance_number,
                           provId[groupIdx].gs_node_number,
                           provId[groupIdx].gs_provider_id);
#endif  /* if ! _VERBOSE_PROVIDER_OUTPUT */
                } else {
#ifndef _VERBOSE_PROVIDER_OUTPUT
                    printf("They tried to expel me [%d/%d] but failed.  HA!\n",
                           provId[groupIdx].gs_instance_number,
                           provId[groupIdx].gs_node_number);
#else
                    /* do not print out the int value. */
                    printf("They tried to expel me [%d/%d(%d)] but failed.  HA!\n",
                           provId[groupIdx].gs_instance_number,
                           provId[groupIdx].gs_node_number,
                           provId[groupIdx].gs_provider_id);
#endif  /* if ! _VERBOSE_PROVIDER_OUTPUT */
                }
            }
        }
    }
 
    /* An expel protocol only carries the leave info on the approval notification. */
 
    if ((HA_GS_FAILURE_LEAVE == note->gs_protocol_type) ||
        (HA_GS_LEAVE == note->gs_protocol_type) ||
        ((HA_GS_EXPEL == note->gs_protocol_type) &&
         (HA_GS_APPROVED_NOTIFICATION == whatItBe)) ||
        (HA_GS_CAST_OUT == note->gs_protocol_type)) {
        printf("LeaveInfo[");
        if (NULL == (leave_array = proposal->gs_leave_info)) {
            printf("No leave info?!?");
        } else {
            leave_info = leave_array->gs_leave_codes;
            for (i = 0; i < leave_array->gs_count; i++) {
                printf("[%d: reason[%s] code[%d]]\n",
                       i,
                       write_leave_reason(leave_info->gs_voluntary_or_failure),
                       leave_info->gs_voluntary_leave_code);
                leave_info++;
            }
        }
        printf("]\n");
    }
 
    /*
     * For an expel, we would have already written the list of targeted
     * providers earlier (they are in the "changing providers" field).  Here,
     * display the deactivate script information - phase and flag.
     */
    if (HA_GS_EXPEL_INFORMATION & whatchanged) {
        if (HA_GS_EXPEL == note->gs_protocol_type) {
            printf("ExpelInfo[");
            if (NULL == (expel_info = proposal->gs_expel_info)) {
                printf("No expel info?!?");
            } else {
                printf("Deactivate script execution phase [%d]\n flag:[%s]",
                       expel_info->gs_deactivate_phase,
                       expel_info->gs_expel_flag);
            }
            printf("]\n");
        } else {
            printf("Have expel information but not an expel protocol notification?!?\n");
        }
    }
 
    /*
     * We make the assumption that we only join the pre-defined set of groups,
     * which will always enforce a set format to their state values:
     *  int
     *  tag
     *  rest of the data.
     * Therefore, we simply display the state value using this format.  If
     * you modify this program to join arbitrary groups, this display method
     * may not properly work.
     *
     * Please refer to the routine "write_arbitrary_value()" where we attempt
     * (weakly) to deal with displaying arbitrary group state values.
     */
 
    state = proposal->gs_current_state_value;
    printf("CurrentState[");
    if (0 >= state->gs_length) {
        printf("No current state!?!");
    } else {
        printf("Length[%d] Value[", state->gs_length);
        memcpy(&stpbmint, &state->gs_state[0], sizeof(stpbmint));
        printf("%d", stpbmint);
        for (i=sizeof(stpbmint); i<state->gs_length; i++) {
            printf("%c",  state->gs_state[i]);
        }
        printf("]");
    }
    printf("]\n");
 
    if ((HA_GS_PROPOSED_STATE_VALUE & whatchanged) ||
        (HA_GS_ONGOING_STATE_VALUE & whatchanged) ||
        (HA_GS_UPDATED_STATE_VALUE & whatchanged)) {
        if ((state = proposal->gs_proposed_state_value) != 0) {
            printf("ProposedState[");
            if (state->gs_length == 0) {
                printf("No proposed state");
            } else {
                printf("Length[%d] Value[", state->gs_length);
                memcpy(&stpbmint, &state->gs_state[0], sizeof(stpbmint));
                printf("%d", stpbmint);
                for (i=sizeof(stpbmint); i<state->gs_length; i++) {
                    printf("%c",  state->gs_state[i]);
                }
                printf("]");
            }
            printf("]\n");
        }
    }
 
    if (HA_GS_UPDATED_PROVIDER_MESSAGE & whatchanged) {
        if ((pbm = proposal->gs_provider_message) != 0) {
            printf("ProviderMessage[");
            if (pbm->gs_length == 0) {
                printf("No message");
            } else {
                printf("Length[%d] Value[", pbm->gs_length);
                memcpy(&stpbmint, &pbm->gs_message[0], sizeof(stpbmint));
                printf("%d", stpbmint);
                for (i=sizeof(stpbmint); i<pbm->gs_length; i++) {
                    printf("%c", pbm->gs_message[i]);
                }
                printf("]");
            }
            printf("]\n");
        }
    }
 
    if (HA_GS_REFLECTED_SOURCE_STATE_VALUE & whatchanged) {
        if ((state = proposal->gs_source_state_value) != 0) {
            printf("SourceState[");
            if (state->gs_length == 0) {
                printf("No source state");
            } else {
                printf("Length[%d] Value[", state->gs_length);
                memcpy(&stpbmint, &state->gs_state[0], sizeof(stpbmint));
                printf("%d", stpbmint);
                for (i=sizeof(stpbmint); i<state->gs_length; i++) {
                    printf("%c",  state->gs_state[i]);
                }
                printf("]");
            }
            printf("]\n");
        }
    }
 
    /* Do we have a new set of group attributes? */
    if ((HA_GS_UPDATED_GROUP_ATTRIBUTES & whatchanged) ||
        (HA_GS_PROPOSED_GROUP_ATTRIBUTES & whatchanged) ||
        (HA_GS_ONGOING_GROUP_ATTRIBUTES & whatchanged) ||
        (HA_GS_REJECTED_GROUP_ATTRIBUTES & whatchanged)) {
 
        if ((HA_GS_PROPOSED_GROUP_ATTRIBUTES & whatchanged) ||
            (HA_GS_ONGOING_GROUP_ATTRIBUTES & whatchanged)) {
            printf("New group attributes proposed for the group!\n");
            write_the_attributes(proposal->gs_new_group_attributes);
        } else if (HA_GS_UPDATED_GROUP_ATTRIBUTES & whatchanged) {
            printf("New group attributes established for the group!\n");
            write_the_attributes(proposal->gs_new_group_attributes);
#ifdef  _SAMPLE_TEST                    /* _SAMPLE_TEST */
            free(gattr[groupIdx]);
            gattr[groupIdx] = malloc(sizeof(ha_gs_group_attributes_t));
            copy_the_attributes(groupIdx,
                                gattr[groupIdx],
                                proposal->gs_new_group_attributes);
#endif                                  /* ifdef _SAMPLE_TEST */
        } else {
            printf("New group attributes rejected for the group!\n");
            write_the_attributes(proposal->gs_new_group_attributes);
        }
    }
 
    printf(asterisks);
    fflush(stdout);
 
    /* End: Write out the data received. */
    return;
}
 
/*
 * Display the protocol proposal information contained in a notification.
 */
void    write_the_proposal(ha_gs_request_t eReq,
                           ha_gs_token_t   eTok,
                           ha_gs_proposal_info_t *prop)
{
    int i, grpIdx;
    ha_gs_provider_t *_expellee;
 
    switch(eReq) {
      case HA_GS_JOIN:
        printf("Join proposal: Instance[%d]  Local name[%s]\n",
               prop->gs_join_request.gs_provider_instance,
               prop->gs_join_request.gs_provider_local_name);
        write_the_attributes(prop->gs_join_request.gs_group_attributes);
        break;
      case HA_GS_STATE_VALUE_CHANGE:
        printf("State change proposal: Number phases[%s]  Time limit[%d]\n",
               phase_print(prop->gs_state_change_request.gs_num_phases),
               prop->gs_state_change_request.gs_time_limit);
        printf("Proposed state: length[%d]\n",
               prop->gs_state_change_request.gs_new_state.gs_length);
        write_arbitrary_value(ARBITRARY_STATE_VALUE,
                              (void *)&(prop->gs_state_change_request.gs_new_state));
        break;
      case HA_GS_PROVIDER_MESSAGE:
        printf("Provider message proposal: Number phases[%s]  Time limit[%d]\n",
               phase_print(prop->gs_message_request.gs_num_phases),
               prop->gs_message_request.gs_time_limit);
        printf("Provider message: length[%d]\n",
               prop->gs_message_request.gs_message.gs_length);
        write_arbitrary_value(ARBITRARY_PROV_MESSAGE,
                              (void *)&(prop->gs_message_request.gs_message));
        break;
      case HA_GS_LEAVE:
        printf("Voluntary leave proposal: Number phases[%s]  Time limit[%d]\n",
               phase_print(prop->gs_leave_request.gs_num_phases),
               prop->gs_leave_request.gs_time_limit);
        printf("Leave code: value[%d]\n",
               prop->gs_leave_request.gs_leave_code);
        break;
      case HA_GS_EXPEL:
        printf("Expel proposal: Number phases[%s]  Time limit[%d]\n",
               phase_print(prop->gs_leave_request.gs_num_phases),
               prop->gs_expel_request.gs_time_limit);
        printf("Deactivate phase[%d] Number of providers[%d]\n",
               prop->gs_expel_request.gs_deactivate_phase,
               prop->gs_expel_request.gs_expel_list.gs_count);
        printf("Targeted providers[");
        for (i = prop->gs_expel_request.gs_expel_list.gs_count,
             	_expellee = prop->gs_expel_request.gs_expel_list.gs_providers;
             0 < i;
             i--, _expellee++) {
#ifndef _VERBOSE_PROVIDER_OUTPUT
            printf("%d/%d ",
                   _expellee->gs_instance_number,
                   _expellee->gs_node_number);
#else
            /* do not print out the int value. */
            printf("%d/%d(%d) ",
                   _expellee->gs_instance_number,
                   _expellee->gs_node_number,
                   _expellee->gs_provider_id);
#endif  /* if ! _VERBOSE_PROVIDER_OUTPUT */
            _expellee++;
        }
        printf("]\n");
        if (NULL != prop->gs_expel_request.gs_deactivate_flag) {
            printf("Deactivate flag[%s]\n",
                   prop->gs_expel_request.gs_deactivate_flag);
        } else {
            printf("No deactivate flag given.\n");
        }
        fflush(stdout);
        break;
      case HA_GS_GROUP_ATTRIBUTE_CHANGE:
        printf("Change attributes proposal: Number of phases[%s]  Time limit[%d]\n",
               phase_print(prop->gs_attribute_change_request.gs_num_phases),
               prop->gs_attribute_change_request.gs_time_limit);
        write_the_attributes(prop->gs_attribute_change_request.gs_group_attributes);
        fflush(stdout);
        break;
      case HA_GS_MERGE:
      case HA_GS_FAILURE_LEAVE:
      case HA_GS_CAST_OUT:
      case HA_GS_SOURCE_STATE_REFLECTION:
        printf("Merge/failure/cast out/reflection protocols should never be here!\n");
        break;
      case HA_GS_SUBSCRIPTION:
        printf("subscription request:\nGroup[%s] Subscription desired[%s]\n",
               prop->gs_subscribe_request.gs_subscription_group,
               write_sub_ctrl(prop->gs_subscribe_request.gs_subscription_control));
#ifdef  _SAMPLE_TEST                    /* _SAMPLE_TEST */
        if (-1 != (i = get_sub_index(eTok))) {
            sid[i] = -1;
            subCtrl[i] = 0;
            free(subNames[i]);
            subNames[i] = 0;
            subscribed_to_count--;
            break;
        } else {
            printf("Received delayed error on unkown subscription token [%d]\n",
                   eTok);
        }
#endif                                  /* ifdef _SAMPLE_TEST */
        break;
 
      default:
        printf("Bad news, bucko.  I don't understand the given request[%d]!\n",
              eReq);
    }
 
    fflush(stdout);
    return;
}
 
/*
 * Display the information contained in a delayed error notification.
 */
void    write_the_delayed_error(const ha_gs_delayed_error_notification_t *note)
{
    ha_gs_token_t   eToken;
    ha_gs_request_t eRequest;
    ha_gs_rc_t      eRC;
 
    eToken = note->gs_request_token;
    eRequest = note->gs_protocol_type;
    eRC = note->gs_delayed_return_code;
 
    printf(starz);
    printf("Very sorry to report that your proposal request is erroneous.\n");
    printf(" Token[%d]  Request[%s]  Return code[%s]\n",
           eToken,
           proto_type(eRequest),
           write_an_rc(eRC));
    write_the_proposal(eRequest, eToken, note->gs_failing_request);
    printf(starz);
    fflush(stdout);
    return;
}
 
#ifdef  _SAMPLE_TEST                    /* _SAMPLE_TEST */
 
/*
 * If it is given, display the "special" data from a subscription
 * notification.
 */
 
void    write_the_special_flag(unsigned int     flag)
{
    if (HA_GS_ADAPTER_DEATH_ARRAY & flag) {
        printf(" HA_GS_ADAPTER_DEATH_ARRAY");
    }
    if (HA_GS_CURRENT_ADAPTER_ALIAS_ARRAY & flag) {
        printf(" HA_GS_CURRENT_ADAPTER_ALIAS_ARRAY");
    }
    if (HA_GS_CHANGING_ADAPTER_ALIAS_ARRAY & flag) {
        printf(" HA_GS_CHANGING_ADAPTER_ALIAS_ARRAY");
    }
 
    return;
}
 
/*
 * We have a set of adapter alias (IP) addresses.  Print each out.
 */
void    write_special_alias_array(const ha_gs_special_block_t *block)
{
    unsigned int *IPaddr;
    int           count, length, increment, i, j, k;
    char         *IPprint;
 
    count = block->gs_special_num_entries;
    length = block->gs_special_length;
    increment = length / 4;
 
    /*
     * Write the addresses in the order given.
     */
 
    IPaddr = (unsigned int *)block->gs_special;
    for (i = 0, j = 0; i < count; i++, j += k) {
        IPprint = inet_ntoa(*(struct in_addr *)IPaddr);
        k = strlen(IPprint) + 1;
        if (80 < (j + k)) {
            printf("\n");
            j = 0;
        }
        printf("%s ", IPprint);
        IPaddr += increment;
    }
    if (0 != j) printf("\n");
    fflush(stdout);
    return;
}
 
/*
 * We have a set of "death reasons" for each specified adapter.
 */
void    write_special_death_array(const ha_gs_special_block_t *block)
{
    ha_gs_adapter_death_t *why_died;
    int           count, length, i, j;
 
    count = block->gs_special_num_entries;
    length = block->gs_special_length;
 
    why_died = (ha_gs_adapter_death_t *)block->gs_special;
    for (i = 0, j = 0; i < count; i++, why_died++) {
        if (HA_GS_ADAPTER_REMOVED == *why_died) {
            printf("%d:Removed! ", i);
            j += 2;
        } else if (HA_GS_ADAPTER_DEAD == *why_died) {
            printf("%d:Died ", i);
            j += 1;
        } else {
            printf("%d:Unknown? ", i);
            j += 2;
        }
        if (8 <= j) {
            printf("\n");
            j = 0;
        }
    }
    if (0 != j) printf("\n");
    fflush(stdout);
    return;
}
 
/*
 * Control writing out the special data.  Find the individual blocks.
 */
void    write_the_special_data(const ha_gs_special_data_t *special)
{
    ha_gs_special_block_t *special_block;
    int block_count;
 
    printf("\nThe subscription has 'special' data.  How special!\n");
    printf("Special data contains [%d] block%s  Flags:\n",
           special->gs_length,
           ((1 == special->gs_length) ? "." : "s."));
    write_the_special_flag(special->gs_flag);
    printf("\nDisplaying data:\n");
 
    special_block = (ha_gs_special_block_t *)special->gs_special_data;
    block_count = 1;
 
    while (NULL != special_block) {
        printf("Special block %d:  Flag:",
               block_count);
        write_the_special_flag(special_block->gs_special_flag);
        printf("\n Number entries [%d]  Entry length [%d]  Data pointer [0x%x]\n",
               special_block->gs_special_num_entries,
               special_block->gs_special_length,
               special_block->gs_special);
        fflush(stdout);
        if (HA_GS_ADAPTER_DEATH_ARRAY & special_block->gs_special_flag) {
            write_special_death_array(special_block);
        } else if (HA_GS_CURRENT_ADAPTER_ALIAS_ARRAY & special_block->gs_special_flag) {
            write_special_alias_array(special_block);
        } else if (HA_GS_CHANGING_ADAPTER_ALIAS_ARRAY & special_block->gs_special_flag) {
            write_special_alias_array(special_block);
        } else {
            printf("Unknown special data block type [%d] !!!\n",
                   special_block->gs_special_flag);
        }
 
        fflush(stdout);
        special_block = special_block->gs_next_special_block;
        block_count++;
    }
 
    return;
}
 
/*
 * Display the information contained in a subscription notification.
 */
void    write_the_subscription(const ha_gs_subscription_notification_t *note)
{
    int i, len, isize;
    int stpbmint, grpIdx, predefSub;
 
    ha_gs_membership_t     *membership;
    ha_gs_provider_t       *provider;
    ha_gs_state_value_t    *state;
 
    printf("**********************************************************************\n");
 
    printf("Type[%s] Token[%d] GroupName[",
           proto_type(HA_GS_SUBSCRIPTION),
           note->gs_subscriber_token);
 
    predefSub = 0;                      /* one of sample_test's predefined groups? */
 
    if (-1 != (grpIdx = get_sub_index(note->gs_subscriber_token))) {
        printf("%s", 
               subNames[grpIdx]);
        for (i = 0;
             ((i < num_groups) && (!predefSub));
             i++) {
            if (!strcmp(group_names[i], subNames[grpIdx])) {
                predefSub = 1;
            }
        }
    } else {
        printf("Unknown!!");
        grpIdx = -2;
    }
    printf("]\n");
 
    write_sub_type(note->gs_subscription_type);
 
    if (HA_GS_SUBSCRIPTION_MEMBERSHIP & note->gs_subscription_type) {
        membership = note->gs_full_membership;
        printf("CurrentProviders[");
        if (membership->gs_count == 0) {
            printf("No providers in list!");
        } else {
            printf("count[%d] Members[", membership->gs_count);
            provider = membership->gs_providers;
            for (i = 0; i < membership->gs_count; i++) {
#ifndef _VERBOSE_PROVIDER_OUTPUT
                printf("%d/%d ",
                       provider->gs_instance_number,
                       provider->gs_node_number);
#else
                /* do not print out the int value. */
                printf("%d/%d(%d) ",
                       provider->gs_instance_number,
                       provider->gs_node_number,
                       provider->gs_provider_id);
#endif  /* if ! _VERBOSE_PROVIDER_OUTPUT */
                provider++;
            }
            printf("]");
        }
        printf("]\n");
    }
 
    if (HA_GS_SUBSCRIPTION_DELTA_JOIN & note->gs_subscription_type) {
        membership = note->gs_changing_membership;
        printf("JoiningProviders[");
        if (membership->gs_count == 0) {
            printf("No changing providers!");
        } else {
            printf("count[%d] Members[", membership->gs_count);
            provider = membership->gs_providers;
            for (i = 0; i < membership->gs_count; i++) {
#ifndef _VERBOSE_PROVIDER_OUTPUT
                printf("%d/%d ",
                       provider->gs_instance_number,
                       provider->gs_node_number);
#else
                /* do not print out the int value. */
                printf("%d/%d(%d) ",
                       provider->gs_instance_number,
                       provider->gs_node_number,
                       provider->gs_provider_id);
#endif  /* if ! _VERBOSE_PROVIDER_OUTPUT */
                provider++;
            }
            printf("]");
        }
        printf("]\n");
    }
    if (HA_GS_SUBSCRIPTION_DELTA_LEAVE & note->gs_subscription_type) {
        membership = note->gs_changing_membership;
        printf("LeavingProviders[");
        if (membership->gs_count == 0) {
            printf("No changing providers!");
        } else {
            printf("count[%d] Members[", membership->gs_count);
            provider = membership->gs_providers;
            for (i = 0; i < membership->gs_count; i++) {
#ifndef _VERBOSE_PROVIDER_OUTPUT
                printf("%d/%d ",
                       provider->gs_instance_number,
                       provider->gs_node_number);
#else
                /* do not print out the int value. */
                printf("%d/%d(%d) ",
                       provider->gs_instance_number,
                       provider->gs_node_number,
                       provider->gs_provider_id);
#endif  /* if ! _VERBOSE_PROVIDER_OUTPUT */
                provider++;
            }
            printf("]");
        }
        printf("]\n");
    }
 
    if (HA_GS_SUBSCRIPTION_STATE & note->gs_subscription_type) {
        state = note->gs_state_value;
        printf("CurrentState[");
        if (0 >= state->gs_length) {
            printf("No current state!?!");
        } else {
            len = state->gs_length;
            printf("Length[%d] Value[", len);
 
            if (predefSub) {
                /*
                 * For the "pre-defined" set of groups, we know that
                 * the format of the state values is predictable.
                 */
                memcpy(&stpbmint, &state->gs_state[0], sizeof(stpbmint));
                printf("%d", stpbmint);
                for (i=sizeof(stpbmint); i<state->gs_length; i++) {
                    printf("%c",  state->gs_state[i]);
                }
            } else {
                write_arbitrary_value(ARBITRARY_STATE_VALUE, (void *)state);
            }
            printf("]");
        }
        printf("]\n");
    }
 
    if (HA_GS_SUBSCRIPTION_SPECIAL_DATA & note->gs_subscription_type) {
        write_the_special_data(note->gs_subscription_special_data);
    }
 
    if (HA_GS_SUBSCRIPTION_DISSOLVED & note->gs_subscription_type) {
        printf("\n Subscription has been DISSOLVED.\n");
        if (HA_GS_SUBSCRIPTION_GS_HAS_DIED & note->gs_subscription_type) {
            printf("   Group Services has gone away, taking all groups with it...\n\n");
        } else {
            printf("   Group has gone away...\n\n");
        }
        if (-2 != grpIdx) {
            sid[grpIdx] = -1;
            subCtrl[grpIdx] = 0;
            free(subNames[grpIdx]);
            subNames[grpIdx] = 0;
            subscribed_to_count--;
        }
    }
 
    printf("**********************************************************************\n");
    fflush(stdout);
 
    return;
}
 
/**********************************************************************/
/*
 * The user wants to subscribe to a group.  Find a free slot in our
 * subscriber token array.
 */
int     find_free_sub_slot()
{
    int i, slot;
 
    for (i = 0;
         i < num_groups_for_subscribe;
         i++) {
        if (-1 == sid[i]) {
            slot = i;
            break;
        }
    }
 
    return(slot);
}
 
/*
 * A subscription notification has arrived.  Find the given token in
 * our subscriber token array.
 */
int     get_sub_index(ha_gs_token_t token)
{
    int  i, found;
 
    found = 0;
    for (i = 0;
         i < num_groups_for_subscribe;
         i++) {
        if (token == sid[i]) {
            found = 1;
            break;
        }
    }
    if (!found) {
        printf("Received subscriber token [%d], but cannot find it in subscription array!\n",
               token);
        i = -1;
    }
 
    return(i);
}
 
/*********************************************************************/
/*
 * These routines are used when the user is interactively constructing
 * a protocol proposal to request the various bits of information
 * needed.
 */
 
/*
 * Determine to which group this proposal request will be directed.
 */
ha_gs_token_t       get_group_token(int *gAddr)
{
    ha_gs_token_t   _gTok;
    int _goodGroup, _insultLevel;
    char _input;
    int _numput;
 
    _gTok = -1;
    _insultLevel = 0;
 
    if (1 == in_group_count) {
        for (_goodGroup = 0;
             num_groups > _goodGroup;
             _goodGroup++) {
            if (in_group[_goodGroup]) {
                _gTok = gid[_goodGroup];
                *gAddr = _goodGroup;
                break;
            }
        }
        printf("I would ask you to which group is this proposal to be targeted, but since\n");
        printf(" you are only in the group named [%s] you are going to use that one!\n",
               group_names[_goodGroup]);
        fflush(stdout);
        return(_gTok);
    }
 
    while (_gTok == -1) {
        printf("You need to specify to which group this proposal is targeted.\n");
        printf(" There are [%d] groups to choose from, choose one by its index number:\n",
               in_group_count);
        fflush(stdout);
        for (_goodGroup = 0;
             num_groups > _goodGroup;
             _goodGroup++) {
            if (in_group[_goodGroup]) {
                printf("  Index[%d]: Group name[%s]\n",
                       _goodGroup,
                       group_names[_goodGroup]);
            }
        }
        printf("Your choice, please?");
        fflush(stdout);
        scanf("%d%c", &_numput, &_input);
        if ((num_groups >= (unsigned int)_numput) && in_group[_numput]) {
            _gTok = gid[_numput];
            *gAddr = _numput;
            printf("You have chosen group [%s].  Good luck.\n",
                   group_names[_numput]);
        } else {
            switch(_insultLevel) {
              case 0:
                printf("I'm sorry, there is no valid group at index [%d]!  Try again!\n",
                       _numput);
                break;
              case 1:
                printf("I'm sorry, there is no valid group at index [%d]!  Concentrate!\n",
                       _numput);
                break;
              case 2:
                printf("Look, [%d] is NOT a valid index.  Read the instructions...\n",
                       _numput);
                break;
              case 3:
                printf("I don't know about you, but I have better things to do than to\n");
                printf("sit in this silly loop with you giving me invalid index values\n");
                printf("such as [%d]!!  Please try one more time.\n",
                       _numput);
                break;
              default:
                printf("I am very sorry.  5 chances to pick %d valid index number.  Buut\n",
                       in_group_count);
                printf("nnoooo.  Well, time to give it up.  I'm outta here.\n");
                return(_gTok);
            }
            fflush(stdout);
            _insultLevel++;
        }
    }
 
    return(_gTok);
}
 
/*
 * Ask for the number of phases (1 or n) for this proposal.
 */
ha_gs_num_phases_t      get_number_of_phases()
{
    int _phases;
    ha_gs_num_phases_t _numPhases;
 
    char    _input, _newline;
    char    _xinline[80];
    char    _intest;
 
    _phases = -1;
 
    while(-1 == _phases) {
        printf("Number of phases('1' or 'N'): "); fflush(stdout);
        gets(_xinline);
        _intest = _xinline[0];
        _phases = 1;
        switch(_intest) {
          case '1':
            _numPhases = HA_GS_1_PHASE;
            break;
          case 'n':
          case 'N':
            _numPhases = HA_GS_N_PHASE;
            break;
          default:
            printf("Very sorry, but [%c] is not acceptable for number of phases.\n",
                   _intest);
            _phases = -1;
        }
    }
 
    return(_numPhases);
}
 
/*
 * Constructing our own group attributes, determine the batch control
 * attribute.
 */
ha_gs_batch_ctrl_t   get_batch_control()
{
    int  _numput, _good;
    char _input, _newline;
 
    printf("Please specify the group's batch control attribute.\n");
    _good = 0;
    while (!_good) {
        printf("Enter: 0 (no batching) 1 (joins only) 2 (failures only) 3 (joins and failures)\n");
	printf("       (add 4 for deact-on-failure, i.e., 5=deact-on-failure & joins)\n");
        fflush(stdout);
        scanf("%d%c", &_numput, &_newline);
        switch(_numput) {
          case 0:
            return(HA_GS_NO_BATCHING);
          case 1:
            return(HA_GS_BATCH_JOINS);
          case 2:
            return(HA_GS_BATCH_LEAVES);
          case 3:
            return(HA_GS_BATCH_BOTH);
	  case 4:
	    return HA_GS_DEACTIVATE_ON_FAILURE;
	  case 5:
	    return HA_GS_DEACTIVATE_ON_FAILURE|HA_GS_BATCH_JOINS;
	  case 6:
	    return HA_GS_DEACTIVATE_ON_FAILURE|HA_GS_BATCH_LEAVES;
	  case 7:
	    return HA_GS_DEACTIVATE_ON_FAILURE|HA_GS_BATCH_BOTH;
          default:
            printf("Invalid batch control entry [%d].  Try again.\n", _numput);
        }
    }
 
    return(HA_GS_NO_BATCHING);
}
 
/*
 * Constructing our own group attributes, determine the base default
 * group vote attribute.
 */
ha_gs_vote_value_t       get_default_vote()
{
    int  _numput, _good;
    char _input, _newline;
 
    printf("Please specify the group's default vote attribute.\n");
    _good = 0;
    while (!_good) {
        printf("Enter: 0 (APPROVE) 1 (REJECT)\n");
        fflush(stdout);
        scanf("%d%c", &_numput, &_newline);
        switch(_numput) {
          case 0:
            return(HA_GS_VOTE_APPROVE);
          case 1:
            return(HA_GS_VOTE_REJECT);
          default:
            printf("Invalid default vote entry [%d].  Try again.\n", _numput);
        }
    }
 
    return(HA_GS_VOTE_APPROVE);
}
 
/*
 * Ask for the time limit to be applied to a protocol proposal.
 */
ha_gs_time_limit_t      get_time_limit(char *_banner)
{
    int  _numput, _gIndex, _good;
    char _input, _newline;
 
    ha_gs_time_limit_t  _time;
 
    printf("Please specify time limit for %s.\n", _banner);
    printf(" In seconds, range 0 (no time limit) to 65,535: ");
    fflush(stdout);
    scanf("%d%c", &_numput, &_newline);
    _time = _numput;
 
    return(_time);
}
 
/*
 * Ask for the group name, for defining our own group, or subscribing to
 * an arbitrary group.
 */
char    *get_group_name(char *_banner)
{
    int  _numput, _gIndex, _good;
    char _input, _newline;
 
    char *_pName;
    char  _nameWanted[80];
 
    printf("Specify %s.\n", _banner);
    fflush(stdout);
    scanf("%s", _nameWanted);
    _pName = malloc(strlen(_nameWanted) + 1);
    strcpy(_pName, _nameWanted);
 
    return(_pName);
}
 
/*
 * Ask for the socket control setting if the user is interactively
 * specifying initialization parameters.
 */
ha_gs_socket_ctrl_t      build_socket_control()
{
    int  _numput, _good;
    char _input, _newline;
 
    printf("Please specify the client's socket control attribute.\n");
    printf("Enter: 0 (NO SIGNAL) other number (NO SIGNAL | WITH ADAPTER INFO) : ");
    fflush(stdout);
    scanf("%d%c", &_numput, &_newline);
    switch(_numput) {
      case 0:
        printf("Using HA_GS_NO_SOCKET_SIGNAL!  Good idea.\n");
        return(HA_GS_SOCKET_NO_SIGNAL);
      default:
        printf("Using HA_GS_SOCKET_NO_SIGNAL | HA_GS_ENABLE_ADAPTER_INFO !\n");
        return(HA_GS_SOCKET_NO_SIGNAL|HA_GS_ENABLE_ADAPTER_INFO);
 
    }
 
    return(HA_GS_SOCKET_NO_SIGNAL);
}
 
/*
 * Ask for the name of the deactivate script if the user is interactively
 * specifying initialization parameters.
 */
char    *build_deact_script(char *default_deact)
{
    int  _numput, _gIndex, _good;
    char _input, _newline;
 
    char *_pName;
    char  _nameWanted[80];
 
    printf("The default deactivate script is[%s].\n  Keep it (0 [no] 1 [yes])? ",
           default_deact);
    scanf("%d%c", &_numput, &_newline);
    if (0 != _numput) {
        printf("Keeping default deactivatate script [%s].\n",
               default_deact);
        fflush(stdout);
        return(default_deact);
    }
 
    printf("Specify new deactivate script path name:\n");
    fflush(stdout);
    scanf("%s", _nameWanted);
    _pName = malloc(strlen(_nameWanted) + 1);
    strcpy(_pName, _nameWanted);
 
    return(_pName);
}
 
/**********************************************************************/
/*
 * These routines handle creating the responsiveness parameters if the
 * user is interactively specifying initialization parameters.
 */
 
/*
 * Display the responsiveness settings to be given on ha_gs_init().
 */
void    display_responsiveness(ha_gs_responsiveness_t *resp)
{
    int i;
    char *ctr;
 
    printf("Responsiveness parameters specified:  Type[%s]\n",
           responsive_print(resp->gs_responsiveness_type));
    
    if (HA_GS_NO_RESPONSIVENESS == resp->gs_responsiveness_type) {
        fflush(stdout);
        return;
    }
 
    printf("Interval[%d seconds] Response time limit[%d seconds]\n",
           resp->gs_responsiveness_interval,
           resp->gs_responsiveness_response_time_limit);
 
    if (HA_GS_COUNTER_RESPONSIVENESS == resp->gs_responsiveness_type) {
        printf(" Counter location[%x] Counter length[%d] Current value[\n",
               resp->gs_counter_location,
               resp->gs_counter_length);
        ctr = (char *)resp->gs_counter_location;
        for (i = 0;
             i < resp->gs_counter_length;
             i++, ctr++) {
            printf("%1.1x", 
                   (void *)ctr);
        }
        printf("]\n");
    }
    fflush(stdout);
 
    return;
}
 
/*
 * Ask the user for the desired responsiveness settings for submission
 * on the ha_gs_init() call.
 */
ha_gs_responsiveness_t   *build_responsiveness(ha_gs_responsiveness_t *def_resp)
{
    ha_gs_responsiveness_t      *_response;
    ha_gs_responsiveness_type_t	 _type;
    unsigned int		 _interval;
    ha_gs_time_limit_t		 _time_limit;
    void			*_location;
    unsigned int		 _length;
 
    int  i,j,ping;
    int  _numput, _gIndex, _good;
    char _input, _newline;
 
    char *_pName;
    char  _nameWanted[80];
    char  _xinline[80];
    char  _intest;
 
    if (!interactiveInit) {
        display_responsiveness(def_resp);
        return(def_resp);
    }
 
    _response = (ha_gs_responsiveness_t *)malloc(sizeof(ha_gs_responsiveness_t));
    memset(_response, '\0', sizeof(ha_gs_responsiveness_t));
 
    printf("What kind of responsiveness?\n 1 [Ping]  2 [Counter]  3 [None]: ");
    scanf("%d%c", &_numput, &_newline);
    if (2 == _numput) {
        printf("Using HA_GS_COUNTER_RESPONSIVENESS (currently not supported by HAGS)!\n");
        fflush(stdout);
        _type = HA_GS_COUNTER_RESPONSIVENESS;
        ping = 0;
    } else if (1 == _numput) {
        printf("Using HA_GS_PING_RESPONSIVENESS.  Good idea.\n");
        fflush(stdout);
        _type = HA_GS_PING_RESPONSIVENESS;
        ping = 1;
    } else {
        printf("No responsiveness checks?  You a coward, or what?\n");
        fflush(stdout);
        _type = HA_GS_NO_RESPONSIVENESS;
        ping = 2;
    }
 
    if (2 > ping) {
 
        printf("Specify the interval (in seconds) between responsiveness checks: ");
        fflush(stdout);
        scanf("%d%c", &_numput, &_newline);
        _interval = _numput;
 
        printf("Specify time limit (in seconds) for response to responsiveness check: ");
        fflush(stdout);
        scanf("%d%c", &_numput, &_newline);
        _time_limit = _numput;
 
        if (1 == ping) {
            _location = 0;
            _length = 0;
        } else {
            printf("Specify counter location for responsiveness check: ");
            fflush(stdout);
            scanf("%x%c", &_location, &_newline);
 
            printf("Specify counter length for responsiveness check: ");
            fflush(stdout);
            scanf("%d%c", &_numput, &_newline);
            _length = _numput;
        }
 
        _response->gs_responsiveness_type = _type;
        _response->gs_responsiveness_interval = _interval;
        _response->gs_responsiveness_response_time_limit = _time_limit;
        _response->gs_counter_location = _location;
        _response->gs_counter_length = _length;
    }
 
    display_responsiveness(_response);
 
    if (HA_GS_NO_RESPONSIVENESS == _type) {
        return(_response);
    }
 
    printf("\nDo you want to respond manually or automatically to all responsiveness\n");
    printf(" notifications?  If auto, then we will always return OK.  If manual, you\n");
    printf(" will be able to specify OK or NOT_OK at notification time.\n");
    printf(" Specify 'A' [auto] or 'M' [manual] (default is auto): ");
    gets(_xinline);
    _intest = _xinline[0];
    switch(_intest) {
      case 'm':
      case 'M':
        printf("Manual responsiveness responses!\n");
        interactiveResponse = 1;
        break;
      default:
        printf("Automatic responsiveness responses!\n");
        interactiveResponse = 0;
    }
    
    return(_response);
}
 
/*
 * A responsiveness notification has arrived.  Ask the user if we
 * should return a "good" (HA_GS_CALLBACK_OK) or "bad" (HA_GS_CALLBACK_NOT_OK)
 * return code.
 */
ha_gs_callback_rc_t       get_response(ha_gs_time_limit_t _time)
{
    int  _numput;
    char _input, _newline;
 
    ha_gs_callback_rc_t  _rc;
 
    printf("Manual responsiveness mode!!!  You have [%d] seconds to respond!\a\a\a\n",
           _time);
    printf("\nSpecify 0 [to say NOT OK] or anything else [to say OK]:\n");
    fflush(stdout);
    scanf("%d%c", &_numput, &_newline);
    switch(_numput) {
      case 0:
        _rc = HA_GS_CALLBACK_NOT_OK;
        break;
      default:
        _rc = HA_GS_CALLBACK_OK;
    }
 
    return(_rc);
}
 
/**********************************************************************/
/*
 * This routine handles dealing with the user to construct the group
 * attributes to be submitted:
 * - on the ha_gs_join() for "user-defined" groups (via the 'b' command).
 * - to change the attributes via ha_gs_change_attributes() (via 'n' command).
 */
ha_gs_group_attributes_t        *build_group_attributes(int _offset, int _changing)
{
    int  _numput, _gIndex, _good;
    char _input, _newline;
 
    ha_gs_num_phases_t  _phases;
    ha_gs_time_limit_t  _time;
 
    ha_gs_group_attributes_t *_attributes;
 
    _good = 1;
    _attributes = malloc(sizeof(ha_gs_group_attributes_t));
 
    _attributes->gs_version = HA_GS_RELEASE;
    _attributes->gs_sizeof_group_attributes = sizeof(ha_gs_group_attributes_t);
 
    if (_changing) {
        printf("You desire to change the group's attributes.  Brave!\n");
    } else {
        printf("Awesome!  You're going to build a group from scratch!  Good move!\n");
    }
 
    printf("Please define your group's attributes in response to each prompt.\n");
    printf(" 'Client version' (any integer): ");
    fflush(stdout);
    scanf("%d%c", &_numput, &_newline);
    _attributes->gs_client_version = _numput;
 
    _attributes->gs_batch_control = get_batch_control();
 
    printf("Please specify the number of phases for joins and failure protocols:\n");
    _attributes->gs_num_phases = get_number_of_phases();
 
    if (HA_GS_N_PHASE == _attributes->gs_num_phases) {
        _attributes->gs_time_limit = get_time_limit("join/failure protocol time limit");
    } else {
        _attributes->gs_time_limit = 0;
    }
 
    _attributes->gs_group_default_vote = get_default_vote();
 
    printf("Please specify the merge control setting:\n");
    printf("\t1:HA_GS_DISSOLVE_MERGE\n");
    printf("\t2:HA_GS_LARGER_MERGE\n");
    printf("\t3:HA_GS_SMALLER_MERGE\n");
    printf("\t4:HA_GS_DONTCARE_MERGE\n");
    printf(" setting desired: ");
    fflush(stdout);
    scanf("%d%c", &_numput, &_newline);
    switch(_numput) {
      case 1:
        _attributes->gs_merge_control = HA_GS_DISSOLVE_MERGE;
        break;
      case 2:
        _attributes->gs_merge_control = HA_GS_LARGER_MERGE;
        break;
      case 3:
        _attributes->gs_merge_control = HA_GS_SMALLER_MERGE;
        break;
      case 4:
        _attributes->gs_merge_control = HA_GS_DONTCARE_MERGE;
        break;
      default:
        _attributes->gs_merge_control = HA_GS_DISSOLVE_MERGE;
    }
 
    if (_changing) {
        _attributes->gs_group_name = NULL;
        _attributes->gs_source_group_name = NULL;
 
        printf("Please specify the number of phases for source-reflection protocols:\n");
        _attributes->gs_source_reflection_num_phases = get_number_of_phases();
 
        if (HA_GS_N_PHASE == _attributes->gs_source_reflection_num_phases) {
            _attributes->gs_source_reflection_time_limit = get_time_limit("source-reflection time limit");
        } else {
            _attributes->gs_source_reflection_time_limit = 0;
        }
 
        return(_attributes);
    }
 
    _attributes->gs_group_name = get_group_name("the group's name");
    group_names[_offset] = malloc(strlen(_attributes->gs_group_name) + 1);
    strcpy(group_names[_offset], _attributes->gs_group_name);
 
    printf("Do you want to specify a source-group name (0[no] 1[yes])? ");
    fflush(stdout);
    scanf("%d%c", &_numput, &_newline);
    if (_numput) {
        _attributes->gs_source_group_name = get_group_name("the source-group's name");
        source_group_names[_offset] = malloc(strlen(_attributes->gs_source_group_name) + 1);
        strcpy(source_group_names[_offset], _attributes->gs_source_group_name);
 
        printf("Please specify the number of phases for source-reflection protocols:\n");
        _attributes->gs_source_reflection_num_phases = get_number_of_phases();
 
        if (HA_GS_N_PHASE == _attributes->gs_source_reflection_num_phases) {
            _attributes->gs_source_reflection_time_limit = get_time_limit("source-reflection time limit");
        } else {
            _attributes->gs_source_reflection_time_limit = 0;
        }
 
    } else {
        _attributes->gs_source_group_name = NULL;
        _attributes->gs_source_reflection_num_phases = HA_GS_1_PHASE;
        _attributes->gs_source_reflection_time_limit = 0;
    }
 
    printf("Please specify the provider instance number\n");
    printf(" (if negative, use as offset and add to [%d]): ",
           instance_numbers[_offset]);
    fflush(stdout);
    scanf("%d%c", &_numput, &_newline);
    if (0 > _numput) {
        instance_numbers[_offset] = (-1 * _numput) + instance_numbers[_offset];
    } else {
        instance_numbers[_offset] = _numput;
    }
 
    prov_local_names[_offset] = get_group_name("the provider's local name");
 
    return(_attributes);
}
 
/**********************************************************************/
/*
 * Request from the user a vote value, in response to an n-phase
 * notification arriving for a group from Group Services.
 */
ha_gs_vote_value_t get_a_vote(int phase)
{
    char  input, error;
    ha_gs_vote_value_t vote;
    char *instruct="nter a vote value: C [Continue]  A [Approve]  R [Reject]\n";
    char *instruct2=" or, to force 'nested' proposals: T [State change] P [PBM]\n";
    char *function;
 
    ha_gs_proposal_info_t info;
    ha_gs_token_t         group_token;
    ha_gs_rc_t            rc;
 
    vote = HA_GS_NULL_VOTE;
 
    while (HA_GS_NULL_VOTE == vote) {
        printf(starz);
        printf(starz);
        printf("%c%s", 'E', instruct);
        printf("%s", instruct2);
        fflush(stdout);
        while (scanf("%c", &input)) {
            switch(input) {
              case 'C':
              case 'c':
                vote = HA_GS_VOTE_CONTINUE;
                break;
              case 'A':
              case 'a':
                vote = HA_GS_VOTE_APPROVE;
                break;
              case 'R':
              case 'r':
                vote = HA_GS_VOTE_REJECT;
                break;
              case 'T':
              case 't':
                error = 't';
                vote = HA_GS_NULL_VOTE;
                break;
              case 'P':
              case 'p':
                error = 'p';
                vote = HA_GS_NULL_VOTE;
                break;
              case '\n':
                continue;
              default:
                printf("I do not understand your given vote value - %c - try again and please\n");
                printf("%c%s", 'e', instruct);
                printf("%s", instruct2);
                fflush(stdout);
                continue;
            }
            break;
        }
        if (HA_GS_NULL_VOTE != vote) {
            printf("You have chosen well, grasshopper. This protocol will ");
            if (HA_GS_VOTE_CONTINUE == vote) {
                printf("continue yet one more phase!\n");
            } else if (HA_GS_VOTE_APPROVE == vote) {
                printf("be approved here and now!\n");
            } else {
                printf("be rejected utterly!\n");
            }
        } else {
            printf("We're in a bad mood aren't we?  Hehehe.\n");
            function="could not create";
            if ('t' == error) {
                if (build_state_change(&group_token, &info)) {
                    function="ha_gs_change_state_value";
                    rc = ha_gs_change_state_value(group_token, &info);
                }
            } else {
                if (build_pbm(&group_token, &info)) {
                    function="ha_gs_send_message";
                    rc = ha_gs_send_message(group_token, &info);
                }
            }
            printf("Your nested %s proposal has been submitted, rc = %s\n",
                   function,
                   write_an_rc(rc));
        }
        printf(starz);
        fflush(stdout);
    }
 
    return(vote);
}
 
/*
 * Construct a group state value (for submission via a call to
 * ha_gs_change_state_value()), in response to a 't' command.
 */
int     build_state_change(ha_gs_token_t *gToken, ha_gs_proposal_info_t *proposal)
{
    int  _numput, _gIndex;
    char _input, _newline;
 
    ha_gs_num_phases_t  _phases;
    ha_gs_time_limit_t  _time;
 
    st_pbm_struct *_state;
    char   *_state2;
    char    _xinline[80];
    char    _intest;
    int     _sLen;       
 
    _phases = -1;
    _time = 0;
 
    printf(starz);
    printf("\nSo, you want to change the group's state value?\n");
    if (0 == in_group_count) {
        printf("Unfortunately, since you haven't yet joined any groups, that wouldn't be\n");
        printf(" a very good idea, would it, bucko?  Try again later, after you convince\n");
        printf(" some group to allow you to join.  Otherwise, leave me alone.\n");
        printf(starz);
        fflush(stdout);
        return(0);
    }
 
    if (-1 == (*gToken = get_group_token(&_gIndex))) {
        return(0);
    }
 
    printf("\nNow that you've chosen group [%s], we need the protocol information:\n",
           group_names[_gIndex]);
 
    _phases = get_number_of_phases();
 
    if (HA_GS_N_PHASE == _phases) {
        _time = get_time_limit("for the state value change protocol");
    } else {
        _time = 0;
    }
 
    printf("Please enter your proposed state value, anything up to 256 bytes:\n");
    fflush(stdout);
    _state = malloc(sizeof(st_pbm_struct));
 
    /* insert prefix.  */
    _state2 = &_state->st_pbm_data[sample_prefix_len];
    _state->st_pbm_index = sample_index;
    memcpy(&_state->st_pbm_data[0], sample_prefix, sample_prefix_len);
 
    gets(_state2);
    _sLen = sizeof(_state->st_pbm_index) + sample_prefix_len;
    if ((_sLen += strlen(_state2)) > 256) {
        printf("Your given state value is %d bytes long, I'm truncating it to 256 bytes.\n",
               _sLen);
        fflush(stdout);
        _sLen = 256;
    }
    printf("You have chosen [%s] with time limit of [%d] and a proposed state of:\n%d%s\n",
           phase_print(_phases),
           _time,
           _state->st_pbm_index,
           _state->st_pbm_data);
 
    printf("Thank you.  Will now submit your proposal.\n");
 
    proposal->gs_state_change_request.gs_num_phases = _phases;
    proposal->gs_state_change_request.gs_time_limit = _time;
    proposal->gs_state_change_request.gs_new_state.gs_length = _sLen;
    proposal->gs_state_change_request.gs_new_state.gs_state = (char *)_state;
 
    printf(starz);
    fflush(stdout);
    return(1);
}
 
/*
 * Construct a provider-broadcast message (for submission via a call to
 * ha_gs_send_message()), in response to a 'p' command.
 */
int     build_pbm(ha_gs_token_t *gToken, ha_gs_proposal_info_t *proposal)
{
    int  _numput, _gIndex;
    char _input, _newline;
 
    ha_gs_num_phases_t  _phases;
    ha_gs_time_limit_t  _time;
 
    st_pbm_struct *_pbm;
    char   *_pbm2;
    char    _xinline[80];
    char    _intest;
    int     _pLen;       
 
    _phases = -1;
    _time = 0;
 
    printf(starz);
    printf("\nSo, you want to ship a provider message?\n");
    if (0 == in_group_count) {
        printf("Unfortunately, since you haven't yet joined any groups, that wouldn't be\n");
        printf(" a very good idea, would it, bucko?  Try again later, after you convince\n");
        printf(" some group to allow you to join.  Otherwise, leave me alone.\n");
        printf(starz);
        fflush(stdout);
        return(0);
    }
 
    if (-1 == (*gToken = get_group_token(&_gIndex))) {
        return(0);
    }
 
    printf("\nNow that you've chosen group [%s], we need the protocol information:\n",
           group_names[_gIndex]);
 
    _phases = get_number_of_phases();
 
    if (HA_GS_N_PHASE == _phases) {
        _time = get_time_limit("for the provider message protocol");
    } else {
        _time = 0;
    }
 
    printf("Please enter your provider message, anything up to 2048 bytes:\n");
    fflush(stdout);
    _pbm = malloc(sizeof(st_pbm_struct));
 
    /* insert prefix.  */
    _pbm2 = &_pbm->st_pbm_data[sample_prefix_len];
    _pbm->st_pbm_index = sample_index;
    memcpy(&_pbm->st_pbm_data[0], sample_prefix, sample_prefix_len);
 
    gets(_pbm2);
    _pLen = sizeof(_pbm->st_pbm_index) + sample_prefix_len;
    if ((_pLen += strlen(_pbm2)) > 2048) {
        printf("Your given message is %d bytes long, I'm truncating it to 2048 bytes.\n",
               _pLen);
        fflush(stdout);
        _pLen = 2048;
    }
    printf("You have chosen [%s] with time limit of [%d] and a provider_message of:\n%d%s\n",
           phase_print(_phases),
           _time,
           _pbm->st_pbm_index,
           _pbm->st_pbm_data);
 
    printf("Thank you.  Will now submit your proposal.\n");
 
    proposal->gs_message_request.gs_num_phases = _phases;
    proposal->gs_message_request.gs_time_limit = _time;
    proposal->gs_message_request.gs_message.gs_length = _pLen;
    proposal->gs_message_request.gs_message.gs_message = (char *)_pbm;
 
    printf(starz);
    fflush(stdout);
    return(1);
}
 
/*
 * Construct the "voluntary leave" (ha_gs_leave()) request, in response
 * to the 'l' command.
 */
int     build_leave_request(ha_gs_token_t *gToken, ha_gs_proposal_info_t *proposal)
{
    int  _numput, _gIndex;
    char _input, _newline;
 
    ha_gs_num_phases_t  _phases;
    ha_gs_time_limit_t  _time;
 
    unsigned int        _leaveCode;
 
    char    _xinline[80];
    char    _intest;
 
    _phases = -1;
    _time = 0;
 
    printf(starz);
    printf("So you want to leave a group?  You leave me, almost, speechless.\n");
    if (0 == in_group_count) {
        printf("Unfortunately, since you haven't yet joined any groups, that wouldn't be\n");
        printf(" a very good idea, would it, bucko?  Try again later, after you convince\n");
        printf(" some group to allow you to join.  Otherwise, leave me alone.\n");
        printf(starz);
        fflush(stdout);
        return(0);
    } else {
        printf("\nQuitter. When your group needs you, you want to run?\n");
    }
 
    if (-1 == (*gToken = get_group_token(&_gIndex))) {
        return(0);
    }
 
    printf("\nNow that you've chosen group [%s], we need the protocol information:\n",
           group_names[_gIndex]);
 
    _phases = get_number_of_phases();
 
    if (HA_GS_N_PHASE == _phases) {
        _time = get_time_limit("for the leave protocol");
    } else {
        _time = 0;
    }
 
    printf("Please enter your voluntary leave code (any integer value).\n");
    fflush(stdout);
    scanf("%d%c", &_numput, &_newline);
    _leaveCode = _numput;
 
    printf("You have chosen [%s] with time limit of [%d] and a leave code of [%d].\n",
           phase_print(_phases),
           _time,
           _leaveCode);
 
    printf("Thank you.  Will now submit your proposal.\n");
 
    proposal->gs_leave_request.gs_num_phases = _phases;
    proposal->gs_leave_request.gs_time_limit = _time;
    proposal->gs_leave_request.gs_leave_code = _leaveCode;
 
    printf(starz);
    fflush(stdout);
    return(1);
}
 
/*
 * Construct the "expel" (ha_gs_expel()) request, in response to the 'e' command.
 */
int     build_expel_request(ha_gs_token_t *gToken, ha_gs_proposal_info_t *proposal)
{
    int  _numput, _numput2, _gIndex;
    char _input, _newline;
 
    ha_gs_num_phases_t  _phases;
    ha_gs_time_limit_t  _time;
 
    int         _numExpelled, _cnt;
    ha_gs_provider_t    *_targets, *_victim;
    short       _instance;
    short       _node;
    int         _deactPhase;
    int         _deactFlagLen;
    char       *_deactFlag;
 
    char    _xinline[300];
    char    _intest;
 
    _phases = -1;
    _time = 0;
 
    printf(starz);
    printf("So you want to expel a provider?  A heartless, but necessary, act.\n");
    if (0 == in_group_count) {
        printf("Unfortunately, since you haven't yet joined any groups, that wouldn't be\n");
        printf(" a very good idea, would it, bucko?  Try again later, after you convince\n");
        printf(" some group to allow you to join.  Otherwise, just too bad.\n");
        printf(starz);
        fflush(stdout);
        return(0);
    } else {
        printf("\nBrutal.  Nuke someone!\n");
    }
 
    if (-1 == (*gToken = get_group_token(&_gIndex))) {
        return(0);
    }
 
    printf("\nNow that you've chosen group [%s], we need the protocol information:\n",
           group_names[_gIndex]);
 
    _phases = get_number_of_phases();
 
    if (HA_GS_N_PHASE == _phases) {
        _time = get_time_limit("for the expel protocol");
    } else {
        _time = 0;
    }
 
    printf("How many providers do you want to expel?\n");
    fflush(stdout);
    scanf("%d%c", &_numput, &_newline);
    _numExpelled = _numput;
    while (0 >= _numExpelled) {
        printf("An expel protocol with no one (count==%d) to expel is kind of useless!\n",
               _numExpelled);
        printf("How many providers to expel?\n");
        fflush(stdout);
        scanf("%d%c", &_numput, &_newline);
        _numExpelled = _numput;
    }
    _targets = _victim = (ha_gs_provider_t *)malloc(sizeof(ha_gs_provider_t) * _numExpelled);
    for (_cnt = 0;
         _cnt < _numExpelled;
         _cnt++) {
        printf("Enter 'instance_number/node_number' of provider number %d: ", _cnt+1);
        fflush(stdout);
        scanf("%d/%d%c", &_numput, &_numput2, &_newline);
        _victim->gs_instance_number = _numput;
        _victim->gs_node_number = _numput2;
        _victim++;
    }   
 
    printf("In which phase should the deactivate script be executed?\n");
    printf(" If 0 (zero) is given, the deactivate script will not be executed.\n");
    if (HA_GS_1_PHASE == _phases) {
        printf(" Since you specified a 1-phase expel, the deactivate script phase\n");
        printf(" must be 0 (zero) or 1 (one).\n");
    }
    while (1) {
        printf("Deactivate script execution phase: ");
        fflush(stdout);
        scanf("%d%c", &_numput, &_newline);
        _deactPhase = _numput;
        if (0 > _deactPhase) {
            printf("Invalid value [%d] given!  Must be greater than or equal to zero!\n",
                   _deactPhase);
        } else if ((HA_GS_1_PHASE == _phases) &&
                   (1 < _deactPhase)) {
            printf("Invalid value [%d] given for 1-phase expel.  Must be 0 or 1.\n",
                   _deactPhase);
        } else {
            break;
        }
        fflush(stdout);
    }
 
    _deactFlag = NULL;
    _deactFlagLen = 0;
    if (0 != _deactPhase) {
        printf("You specified a non-zero deactivate script execution phase (%d).\n");
        printf(" Do you want to specify a deactivate script flag (0 [no] -- 1 [yes]? ");
        fflush(stdout);
        scanf("%d%c", &_numput, &_newline);
        if ((_numput) && ('n' != _numput)) {
            printf(" Enter flag (maximum 256 bytes): ");
            gets(_xinline);
            _deactFlagLen = strlen(_xinline);
            _deactFlag = malloc(_deactFlagLen + 1);
            strcpy(_deactFlag, _xinline);
        }
    }
 
    printf("You have chosen [%s] with time limit of [%d] and a deactivation phase of [%d].\n",
           phase_print(_phases),
           _time,
           _deactPhase);
    if (NULL != _deactFlag) {
        printf(" Deactivation script flag: %s\n",
               _deactFlag);
    }
    printf("Providers being expelled: count [%d] victim%s[",
           _numExpelled,
           ((1 != _numExpelled) ? "s " : " "));
    _victim = _targets;
    for (_cnt = 0; _cnt < _numExpelled; _cnt++) {
#ifndef _VERBOSE_PROVIDER_OUTPUT
        printf("%d/%d ",
               _victim->gs_instance_number,
               _victim->gs_node_number);
#else
        /* do not print out the int value. */
        printf("%d/%d(%d) ",
               _victim->gs_instance_number,
               _victim->gs_node_number,
               _victim->gs_provider_id);
#endif  /* if ! _VERBOSE_PROVIDER_OUTPUT */
        _victim++;
    }
    printf("]\n");
 
    printf("Thank you.  Will now submit your proposal.\n");
 
    proposal->gs_expel_request.gs_num_phases = _phases;
    proposal->gs_expel_request.gs_time_limit = _time;
    proposal->gs_expel_request.gs_expel_list.gs_count = _numExpelled;
    proposal->gs_expel_request.gs_expel_list.gs_providers = _targets;
    proposal->gs_expel_request.gs_deactivate_phase = _deactPhase;
    proposal->gs_expel_request.gs_deactivate_flag = _deactFlag;
 
    printf(starz);
    fflush(stdout);
    return(1);
}
 
/*
 * Construct a new set of group attributes (for submission via a call to
 * ha_gs_change_attributes()), in response to a 'n' command.
 */
int     build_attributes_change(ha_gs_token_t *gToken, ha_gs_proposal_info_t *proposal)
{
    int  _numput, _gIndex;
    char _input, _newline;
 
    ha_gs_num_phases_t  _phases;
    ha_gs_time_limit_t  _time;
 
    ha_gs_group_attributes_t *_attributes;
 
    _phases = -1;
    _time = 0;
 
    printf(starz);
    printf("\nSo, you want to change the group's attributes?\n");
    if (0 == in_group_count) {
        printf("Unfortunately, since you haven't yet joined any groups, that wouldn't be\n");
        printf(" a very good idea, would it, bucko?  Try again later, after you convince\n");
        printf(" some group to allow you to join.  Otherwise, leave me alone.\n");
        printf(starz);
        fflush(stdout);
        return(0);
    }
 
    if (-1 == (*gToken = get_group_token(&_gIndex))) {
        return(0);
    }
 
    printf("\nNow that you've chosen group [%s], we need the protocol information:\n",
           group_names[_gIndex]);
 
    _phases = get_number_of_phases();
 
    if (HA_GS_N_PHASE == _phases) {
        _time = get_time_limit("for the attribute change protocol");
    } else {
        _time = 0;
    }
 
    _attributes = build_group_attributes(0, 1);
 
    printf("You have chosen [%s] with time limit of [%d] and attributes:\n",
           phase_print(_phases),
           _time);
    write_the_attributes(_attributes);
 
    printf("Thank you.  Will now submit your proposal.\n");
 
    proposal->gs_attribute_change_request.gs_num_phases = _phases;
    proposal->gs_attribute_change_request.gs_time_limit = _time;
    proposal->gs_attribute_change_request.gs_group_attributes = _attributes;
 
    printf(starz);
    fflush(stdout);
    return(1);
}
 
/*
 * Determine which group we want to separate ourself from, prior to
 * calling ha_gs_goodbye(), in response to a 'y' command.
 */
int     build_goodbye_request(ha_gs_token_t *gToken)
{
    int  _numput, _gIndex;
    char _input, _newline;
 
    printf(starz);
    printf("\nSo, you want to say goodbye to a group?\n");
    if (0 == in_group_count) {
        printf("Unfortunately, since you haven't yet joined any groups, that wouldn't be\n");
        printf(" a very good idea, would it, bucko?  Try again later, after you convince\n");
        printf(" some group to allow you to join.  Otherwise, leave me alone.\n");
        printf(starz);
        fflush(stdout);
        return(0);
    }
 
    if (-1 == (*gToken = get_group_token(&_gIndex))) {
        return(0);
    }
    return(1);
}
 
/*
 * We received OK from an ha_gs_goodbye() request, thus, we are out
 * of the group.  Glory days are here again!  Need to clean up the
 * various structures that we keep for each group.
 *
 * The work here is that the gToken is the "provider_id" for the
 * group we just exited, but, we need a reverse lookup into the
 * group table, which is not indexed by the provider_id.  So, walk
 * the table until we find the specified provider_id.
 */
void    told_group_goodbye(ha_gs_token_t gToken)
{
    ha_gs_token_t   _gTok;
    int _goodGroup, _insultLevel;
    int _numput;
 
    for (_goodGroup = 0;
         num_groups > _goodGroup;
         _goodGroup++) {
        if ((in_group[_goodGroup]) && (gToken == gid[_goodGroup])) {
            break;
        }
    }
 
    printf("You have successfully told group \"%s\" goodbye and are no longer a member in it.\n",
           group_names[_goodGroup]);
    fflush(stdout);
    provId[_goodGroup].gs_provider_id = -1;
    in_group[_goodGroup] = 0;
    in_group_count--;
 
    return;
}
 
/**********************************************************************/
/*
 * This routine is used to determine if we will be submitting a changed
 * state value and/or provider-broadcast message when we submit a vote.
 *
 * If values are given, then set those to be used.  If values are not
 * given, then get them from the proper arrays:
 *      provider_msg_array[] -- for provider-broadcast messages.
 *      state_value_array[] -- for group state values.
 */
void    create_state_and_pbm(int        index,
                             ha_gs_state_value_t **_sValue,
                             ha_gs_provider_message_t **_pValue,
                             ha_gs_state_value_t *_srcState,
                             ha_gs_provider_message_t *_srcPBM)
{
    ha_gs_state_value_t      *_s2, *_s3;
    ha_gs_provider_message_t *_p2, *_p3;
 
    char *_cPtr;
 
    if (-1 == index) {
        _s2 = _srcState;                /* values given.  use these. */
        _p2 = _srcPBM;
    } else {
        _s2 = &state_value_array[index]; /* pull from array. */
        _p2 = &provider_msg_array[index];
    }
 
    _s3 = malloc(sizeof(ha_gs_state_value_t));
    if (0 == _s2->gs_length) {
        _s3->gs_length = 0;
        _s3->gs_state = 0;
    } else {
        _s3->gs_length = _s2->gs_length + sample_prefix_len + sizeof(sample_index);
        _s3->gs_state = _cPtr = malloc(_s3->gs_length);
        memcpy(_s3->gs_state, &sample_index, sizeof(sample_index));
        memcpy(_s3->gs_state + sizeof(sample_index), sample_prefix, sample_prefix_len);
        _cPtr += sample_prefix_len + sizeof(sample_index);
        memcpy(_cPtr, _s2->gs_state, _s2->gs_length);
    }
    *_sValue = _s3;
 
    _p3 = malloc(sizeof(ha_gs_provider_message_t));
    if (0 == _p2->gs_length) {
        _p3->gs_length = 0;
        _p3->gs_message = 0;
    } else {
        _p3->gs_length = _p2->gs_length + sample_prefix_len + sizeof(sample_index);
        _p3->gs_message = _cPtr = malloc(_p3->gs_length);
        memcpy(_p3->gs_message, &sample_index, sizeof(sample_index));
        memcpy(_p3->gs_message + sizeof(sample_index), sample_prefix, sample_prefix_len);
        _cPtr += sample_prefix_len + sizeof(sample_index);
        memcpy(_cPtr, _p2->gs_message, _p2->gs_length);
    }
    *_pValue = _p3;
 
    return;
}
 
/**********************************************************************/
/*
 * User wants to subscribe to a group.  Determine the group name and
 * also the subscription control setting.
 */
ha_gs_rc_t      subscribe_to_a_group()
{
    int i, j, grpIdx, idx;
    char *pName;
 
    ha_gs_proposal_info_t info;
 
    ha_gs_subscription_ctrl_t subCtl;
    ha_gs_rc_t                subRC;
    ha_gs_token_t             subToken;
 
    int   wantToPick;
    char  nameWanted[80];
 
    grpIdx = -1;
 
    if (NUM_GROUPS_FOR_SUBSCRIBE <= subscribed_to_count) {
        printf("\nYou cannot subscribe to any more groups!\n");
        return(HA_GS_NOT_OK);
    }
 
    while (-1 == grpIdx) {
        printf("Groups available for subscription.  Specify index of group:\n");
        printf("%5s   %-16s%10s   %-16s\n", "index", "name", "index", "name");
        for (i = 0;
             predef_groups_for_subscribe > i;
             i += 2) {
            printf("%5d   %-16s",
                   i,
                   group_names[i]);
            if (predef_groups_for_subscribe > (i+1)) {
                printf("%10d   %-16s\n",
                       i + 1,
                       group_names[i+1]);
            } else {
                printf("\n");
            }
        }
        printf("%5d   %s\n",
               pickIdx,
               "Specify a group name");
        printf("%5d   %s\n",
               listIdx,
               "List current subscriptions");
 
        printf("Desired index: ");
        fflush(stdout);
 
        scanf("%d", &j);
 
        if (j == listIdx) {
            if (0 == subscribed_to_count) {
                printf("No current subscriptions!\n");
            } else {
                printf("Current subscriptions:\n%5s   %20s     %s\n",
                       "index",
                       "group name",
                       "current subscriptions");
                for (i = 0;
                     num_groups_for_subscribe > i;
                     i++) {
                    if (-1 != sid[i]) {
                        printf("%5d   %20s     %s\n",
                               i,
                               subNames[i],
                               write_sub_ctrl(subCtrl[i]));
                    }
                }
            }
            fflush(stdout);
        } else if ((j != pickIdx) &&
                   ((0 > j) || (j >= num_groups_for_subscribe))) {
            printf("Um, sorry about this, but the index [%d] is invalid.  Try again.\n",
                   j);
        } else {
            grpIdx = j;
        }
    }
 
    wantToPick = (grpIdx == pickIdx);
 
    if (wantToPick) {
        pName = get_group_name("group name for subscription");
        printf("You are subscribing to group [%s]!  Specify subscription type:\n",
               pName);
    } else {
        printf("You are subscribing to group [%s]!  Specify subscription type:\n",
               group_names[grpIdx]);
    }
    subCtl = (ha_gs_subscription_ctrl_t) 0;
 
    while (0 == subCtl) {
        printf("Specify a value between %d and %d.  You may specify one of the specific\n",
               HA_GS_SUBSCRIBE_STATE, HA_GS_SUBSCRIBE_STATE_AND_MEMBERSHIP);
        printf("following flag values, or combine them.\n");
        printf("Value:   Subscription control:\n");
        printf("%5d   %s\n",
               HA_GS_SUBSCRIBE_STATE,
               write_sub_ctrl(HA_GS_SUBSCRIBE_STATE));
        printf("%5d   %s\n",
               HA_GS_SUBSCRIBE_DELTA_JOINS,
               write_sub_ctrl(HA_GS_SUBSCRIBE_DELTA_JOINS));
        printf("%5d   %s\n",
               HA_GS_SUBSCRIBE_DELTA_LEAVES,
               write_sub_ctrl(HA_GS_SUBSCRIBE_DELTA_LEAVES));
        printf("%5d   %s\n",
               HA_GS_SUBSCRIBE_DELTAS_ONLY,
               write_sub_ctrl(HA_GS_SUBSCRIBE_DELTAS_ONLY));
        printf("%5d   %s\n",
               HA_GS_SUBSCRIBE_MEMBERSHIP,
               write_sub_ctrl(HA_GS_SUBSCRIBE_MEMBERSHIP));
        printf("%5d   %s\n",
               HA_GS_SUBSCRIBE_ALL_MEMBERSHIP,
               write_sub_ctrl(HA_GS_SUBSCRIBE_ALL_MEMBERSHIP));
        printf("%5d   %s\n",
               HA_GS_SUBSCRIBE_STATE_AND_MEMBERSHIP,
               write_sub_ctrl(HA_GS_SUBSCRIBE_STATE_AND_MEMBERSHIP));
        printf("\nYour choice: ");
        fflush(stdout);
        
        scanf("%d", &j);
 
        if ((HA_GS_SUBSCRIBE_STATE > j) || (j > HA_GS_SUBSCRIBE_STATE_AND_MEMBERSHIP)) {
            printf("Um, sorry about this, but the index [%d] is out of range.  Try again.\n",
                   j);
        } else {
            subCtl = (ha_gs_subscription_ctrl_t)j;
        }
    }
 
    if (wantToPick) {
        info.gs_subscribe_request.gs_subscription_control = subCtl;
        info.gs_subscribe_request.gs_subscription_group = pName;
        info.gs_subscribe_request.gs_subscription_callback = pickCallback;
    } else {
        info.gs_subscribe_request.gs_subscription_control = subCtl;
        info.gs_subscribe_request.gs_subscription_group = group_names[grpIdx];
        info.gs_subscribe_request.gs_subscription_callback = subCallbacks[grpIdx];
    }
 
    subRC = ha_gs_subscribe(&subToken,
                            &info);
 
    if (HA_GS_OK == subRC) {
        idx = find_free_sub_slot();
        printf("Subscription request accepted.  Token == %d\n", subToken);
        sid[idx] = subToken;
        subCtrl[idx] = subCtl;
 
        if (wantToPick) {
            subNames[idx] = malloc(strlen(pName) + 1);
            strcpy(subNames[idx], pName);
            free(pName);
        } else {
            subNames[idx] = malloc(strlen(group_names[grpIdx]) + 1);
            strcpy(subNames[idx], group_names[grpIdx]);
        }
 
        subscribed_to_count++;
        if (NUM_GROUPS_FOR_SUBSCRIBE <= subscribed_to_count) {
            printf("\nYou cannot subscribe to any more groups!\n");
        }
    } else {
        printf("Problem with subscription: %s\n",
               write_an_rc(subRC));
    }
 
    printf(starz);
    fflush(stdout);
    return(subRC);
}
 
/*
 * User wants to unsubscribe from a group.  Determine which group.
 */
extern  ha_gs_rc_t      unsubscribe_from_a_group()
{
    int i, j, grpIdx;
 
    ha_gs_subscription_ctrl_t subCtl;
    ha_gs_rc_t                subRC;
    ha_gs_token_t             subToken;
 
    grpIdx = -1;
 
    if (0 == subscribed_to_count) {
        printf("\nYou have no current subscriptions.  Cannot unsubscribe!\n\n");
        printf(starz);
        fflush(stdout);
        return(HA_GS_OK);
    }
 
    while (-1 == grpIdx) {
        printf("You are currently subscribed to the following.  Specify an index:\n");
        printf("%5s %20s Current subscriptions\n", "index", "name");
        for (i = 0;
             num_groups_for_subscribe > i;
             i++) {
            if (-1 != sid[i]) {
                printf("%5d %20s %s\n",
                       i,
                       subNames[i],
                       write_sub_ctrl(subCtrl[i]));
            }
        }
 
        printf("Desired index: ");
        fflush(stdout);
 
        scanf("%d", &j);
 
        if ((0 > j) || (j >= num_groups_for_subscribe) || (-1 == sid[j])) {
            printf("Um, sorry about this, but the index [%d] is invalid.  Try again.\n",
                   j);
        } else {
            grpIdx = j;
        }
    }
 
    printf("You wish to unsubscribe from group [%s]!\n",
           subNames[grpIdx]);
 
    subRC = ha_gs_unsubscribe(sid[grpIdx]);
 
    if (HA_GS_OK == subRC) {
        printf("Unsubscription request accepted.  Token[%d], group[%s]\n",
               sid[grpIdx],
               subNames[grpIdx]);
        sid[grpIdx] = -1;
        subCtrl[grpIdx] = 0;
        free(subNames[grpIdx]);
        subNames[grpIdx] = 0;
        subscribed_to_count--;
    } else {
        printf("Problem with unsubscription: %s\n",
               write_an_rc(subRC));
    }
 
    printf(starz);
    fflush(stdout);
    return(subRC);
}
 
/**********************************************************************/
/*
 * Initialize the data fields for setting up subscriptions to the
 * "System Membership" groups.
 */
void init_membership_subscriptions()
{
    /* Set up names for subscribing to system membership groups. */
 
    char *_temp;
 
    /* Only host membership for now. */
 
    _temp = malloc(strlen(HA_GS_HOST_MEMBERSHIP_GROUP) + 1);
    strcpy(_temp, HA_GS_HOST_MEMBERSHIP_GROUP);
    group_names[num_groups] = _temp;
 
    _temp = malloc(strlen(HA_GS_ENET_MEMBERSHIP_GROUP) + 1);
    strcpy(_temp, HA_GS_ENET_MEMBERSHIP_GROUP);
    group_names[num_groups + 1] = _temp;
 
    _temp = malloc(strlen(HA_GS_CSS_MEMBERSHIP_GROUP) + 1);
    strcpy(_temp, HA_GS_CSS_MEMBERSHIP_GROUP);
    group_names[num_groups + 2] = _temp;
 
    _temp = malloc(strlen(HA_GS_TOKENRING_MEMBERSHIP_GROUP) + 1);
    strcpy(_temp, HA_GS_TOKENRING_MEMBERSHIP_GROUP);
    group_names[num_groups + 3] = _temp;
 
    _temp = malloc(strlen(HA_GS_FDDI_MEMBERSHIP_GROUP) + 1);
    strcpy(_temp, HA_GS_FDDI_MEMBERSHIP_GROUP);
    group_names[num_groups + 4] = _temp;
 
    _temp = malloc(strlen(HA_GS_RS232_MEMBERSHIP_GROUP) + 1);
    strcpy(_temp, HA_GS_RS232_MEMBERSHIP_GROUP);
    group_names[num_groups + 5] = _temp;
 
    _temp = malloc(strlen(HA_GS_TMSCSI_MEMBERSHIP_GROUP) + 1);
    strcpy(_temp, HA_GS_TMSCSI_MEMBERSHIP_GROUP);
    group_names[num_groups + 6] = _temp;
 
    _temp = malloc(strlen(HA_GS_SLIP_MEMBERSHIP_GROUP) + 1);
    strcpy(_temp, HA_GS_SLIP_MEMBERSHIP_GROUP);
    group_names[num_groups + 7] = _temp;
 
    _temp = malloc(strlen(HA_GS_MYRINET_MEMBERSHIP_GROUP) + 1);
    strcpy(_temp, HA_GS_MYRINET_MEMBERSHIP_GROUP);
    group_names[num_groups + 8] = _temp;
 
    _temp = malloc(strlen(HA_GS_CSS1_MEMBERSHIP_GROUP) + 1);
    strcpy(_temp, HA_GS_CSS1_MEMBERSHIP_GROUP);
    group_names[num_groups + 9] = _temp;
    return;
}
ha_gs_rc_t get_adapter_info()
{
    int rc = HA_GS_NOT_OK;
    ha_gs_adapter_info _ip;
    char ip_name[30],*ipstr;
 
    memset( &_ip, 0, sizeof(_ip) );
    _ip.interface_name = 0;
    _ip.node_number=-1;
    printf("Enter ip address:(e.g.9.114.67.71)\n");
    scanf("%s",ip_name);
    ipstr = calloc(strlen(ip_name)+1,sizeof(char));
    strcpy(ipstr,ip_name);
 
    printf("%s\n",ipstr);
    _ip.ip_addr.ip4.s_addr=inet_addr(ipstr);
    rc=ha_gs_get_adapter_info(&_ip);
    write_an_rc( rc );
 
    printf("ip:%d,node:%d,type:%s\n",_ip.ip_addr.ip4.s_addr,_ip.node_number, 
	  ( _ip.interface_name ? _ip.interface_name : " ") );
    return rc;
}
ha_gs_rc_t get_local_node_number()
{
    int rc, nodeNum = -1;
 
    rc = ha_gs_get_node_number(&nodeNum);
    write_an_rc( rc );
 
    printf("[node_number=%d]\n",nodeNum);
    return rc;
}
 
 
#endif                                  /* ifdef _SAMPLE_TEST */
 


[ Top of Page | Previous Page | Next Page | Table of Contents | Index ]