/* $Header: /afs/sipb.mit.edu/project/sipb-athena/repository/src/moira/gen/zephyr.dc,v 1.2 1996/06/02 07:42:59 ghudson Exp $
 *
 * This generates zephyr acl files
 *
 *  (c) Copyright 1990 by the Massachusetts Institute of Technology.
 *  For copying and distribution information, please see the file
 *  <mit-copyright.h>.
 */

#include <mit-copyright.h>
#include <stdio.h>
#include <moira.h>
#include <moira_site.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
EXEC SQL INCLUDE sqlca;

extern int errno;
char *whoami = "zephyr.gen";

char zephyr_dir[BUFSIZ];


main(argc, argv)
int argc;
char **argv;
{
    struct stat sb;
    int changed;
    char cmd[256];

    if (argc > 2) {
	fprintf(stderr, "usage: %s [outfile]\n", argv[0]);
	exit(MR_ARGS);
    }

    sprintf(zephyr_dir, "%s/zephyr", DCM_DIR);

#ifsql INGRES
    EXEC SQL CONNECT moira;
    EXEC SQL SET LOCKMODE SESSION WHERE LEVEL=TABLE, READLOCK=SHARED;
#endsql
#ifsql INFORMIX
    EXEC SQL DATABASE moira;
#endsql

    changed = do_classes();

#ifsql INGRES
    EXEC SQL DISCONNECT;
#endsql    
#ifsql INFORMIX
    EXEC SQL CLOSE DATABASE;
#endsql

    if (!changed) {
	fprintf(stderr, "No files updated.\n");
	if (argc == 2 && stat(argv[1], &sb) == 0)
	  exit(MR_NO_CHANGE);
    }

    if (argc == 2) {
	fprintf(stderr, "Building tar file.\n");
	sprintf(cmd, "cd %s; tar cf %s .", zephyr_dir, argv[1]);
	if (system(cmd))
	  exit(MR_TAR_FAIL);
    }

    exit(MR_SUCCESS);
}


struct zclass {
    char class[17];
    char xtype[9];
    char stype[9];
    char wtype[9];
    char utype[9];
    int xid;
    int sid;
    int wid;
    int uid;
    struct zclass *next;
};


int do_classes()
{
    FILE *out;
    char outclass[256], buf[256];
    struct zclass *top, *next, *zc;
    struct stat sb;
    int flag1, flag2;
    EXEC SQL BEGIN DECLARE SECTION;
    char zclass[17], zxtype[9], zstype[9], zwtype[9], zutype[9];
    int zxid, zsid, zwid, zuid;
    EXEC SQL END DECLARE SECTION;

    sprintf(outclass, "%s/class-registry.acl", zephyr_dir);
    if (stat(outclass, &sb) == 0) {
	if (ModDiff(&flag1, "zephyr", sb.st_mtime) ||
	    ModDiff(&flag2, "imembers", sb.st_mtime))
	  exit(MR_DATE);
	if (flag1 < 0 && flag2 < 0) {
	    fprintf(stderr, "Zephyr files do not need to be rebuilt.\n");
	    return(0);
	}
    }

    sprintf(buf, "%s~", outclass);
    out = fopen(buf, "w");
    if (out == NULL) {
	perror("opening class-registry.acl");
	exit(MR_OCONFIG);
    }
    top = (struct zclass *)malloc(sizeof(struct zclass));
    next = top;

    /* The following is declarative, not executed,
     * and so is dependent on where it is in the file,
     * not in the order of execution of statements.
     */
    EXEC SQL WHENEVER SQLERROR GOTO sqlerr;
    EXEC SQL DECLARE classes CURSOR FOR SELECT class, xmt_type, xmt_id,
    	sub_type, sub_id, iws_type, iws_id, iui_type, iui_id
      FROM zephyr;
    EXEC SQL OPEN classes;
    while (1) {
	EXEC SQL FETCH classes INTO
	  :zclass, :zxtype, :zxid, :zstype, :zsid,
	  :zwtype, :zwid, :zutype, :zuid;
	if (sqlca.sqlcode != 0) break;
	zc = (struct zclass *)malloc(sizeof(struct zclass));
	next->next = zc;
	next = zc;
	strcpy(zc->class, zclass);
	strcpy(zc->xtype, zxtype);
	strcpy(zc->stype, zstype);
	strcpy(zc->wtype, zwtype);
	strcpy(zc->utype, zutype);
	zc->xid = zxid;
	zc->sid = zsid;
	zc->wid = zwid;
	zc->uid = zuid;
    }
    if (sqlca.sqlcode != 100) {
	fprintf(stderr, "DBMS error %d\n", sqlca.sqlcode);
	exit(MR_INGRES_ERR);
    }
    EXEC SQL CLOSE classes;
    for (zc = top->next; zc; zc = zc->next) {
	fprintf(out, "%s:\n", strtrim(zc->class));
	fprintf(stderr, "Working on %s\n", zc->class);
	if (!strcasecmp(strtrim(zc->xtype), "LIST")) {
	    getlist(zc->xid, zc->class, "xmt");
	} else if (!strcasecmp(zc->xtype, "KERBEROS")) {
	    getstring(zc->xid, zc->class, "xmt");
	} else if (!strcasecmp(zc->xtype, "USER")) {
	    getuser(zc->xid, zc->class, "xmt");
	} else if (!strcasecmp(zc->xtype, "NONE")) {
	    getnone(zc->class, "xmt");
	}
	if (!strcasecmp(strtrim(zc->stype), "LIST")) {
	    getlist(zc->sid, zc->class, "sub");
	} else if (!strcasecmp(zc->stype, "KERBEROS")) {
	    getstring(zc->sid, zc->class, "sub");
	} else if (!strcasecmp(zc->stype, "USER")) {
	    getuser(zc->sid, zc->class, "sub");
	} else if (!strcasecmp(zc->stype, "NONE")) {
	    getnone(zc->class, "sub");
	}
	if (!strcasecmp(strtrim(zc->wtype), "LIST")) {
	    getlist(zc->wid, zc->class, "iws");
	} else if (!strcasecmp(zc->wtype, "KERBEROS")) {
	    getstring(zc->wid, zc->class, "iws");
	} else if (!strcasecmp(zc->wtype, "USER")) {
	    getuser(zc->wid, zc->class, "iws");
	} else if (!strcasecmp(zc->wtype, "NONE")) {
	    getnone(zc->class, "iws");
	}
	if (!strcasecmp(strtrim(zc->utype), "LIST")) {
	    getlist(zc->uid, zc->class, "iui");
	} else if (!strcasecmp(zc->utype, "KERBEROS")) {
	    getstring(zc->uid, zc->class, "iui");
	} else if (!strcasecmp(zc->utype, "USER")) {
	    getuser(zc->uid, zc->class, "iui");
	} else if (!strcasecmp(zc->utype, "NONE")) {
	    getnone(zc->class, "iui");
	}
    }
    fclose(out);
    fix_file(outclass);
    return(1);
 sqlerr:
    com_err(whoami, MR_INGRES_ERR, " code %d\n", sqlca.sqlcode);
    critical_alert("DCM", "Zephyr build encountered DATABASE ERROR %d",
		   sqlca.sqlcode);
    exit(MR_INGRES_ERR);
}


getlist(list_id, zclass, atype)
int list_id;
char *zclass;
char *atype;
{
    char ofile[256], buf[256];
    FILE *out;
    EXEC SQL BEGIN DECLARE SECTION;
    char str[257];
    int zid;
    EXEC SQL END DECLARE SECTION;

    zid = list_id;
    sprintf(ofile, "%s/%s-%s.acl", zephyr_dir, atype, zclass);
    fprintf(buf, "%s~", ofile);
    out = fopen(buf, "w");
    if (out == NULL) {
	perror("opening acl file");
	exit(MR_OCONFIG);
    }

    EXEC SQL DECLARE umember CURSOR FOR SELECT users.login
      FROM users, imembers
      WHERE imembers.list_id = :zid and imembers.member_type='USER' and
	imembers.member_id=users.users_id;
    EXEC SQL OPEN umember;
    while (1) {
	EXEC SQL FETCH umember INTO :str;
	if (sqlca.sqlcode != 0) break;
	fprintf(out, "%s\n", strtrim(str));
    }
    if (sqlca.sqlcode != 100) {
	fprintf(stderr, "DBMS error %d\n", sqlca.sqlcode);
	exit(MR_INGRES_ERR);
    }
    EXEC SQL CLOSE umember;

    EXEC SQL DECLARE smember CURSOR FOR SELECT strings.string
      FROM strings, imembers
      WHERE imembers.list_id = :zid and imembers.member_id=strings.string_id
	and (imembers.member_type='STRING' or imembers.member_type='KERBEROS');
    EXEC SQL OPEN smember;
    while (1) {
	EXEC SQL FETCH smember INTO :str;
	if (sqlca.sqlcode != 0) break;
	fprintf(out, "%s\n", strtrim(str));
    }
    if (sqlca.sqlcode != 100) {
	fprintf(stderr, "DBMS error %d\n", sqlca.sqlcode);
	exit(MR_INGRES_ERR);
    }
    EXEC SQL CLOSE smember;
    if (fclose(out)) {
	perror("closing acl file");
	exit(MR_CCONFIG);
    }
    fix_file(ofile);
    return;
 sqlerr:
    com_err(whoami, MR_INGRES_ERR, " code %d\n", sqlca.sqlcode);
    critical_alert("DCM", "Zephyr build encountered DATABASE ERROR %d",
		   sqlca.sqlcode);
    exit(MR_INGRES_ERR);
}

getstring(string_id, zclass, atype)
int string_id;
char *zclass;
char *atype;
{
    char ofile[256], buf[256];
    FILE *out;
    EXEC SQL BEGIN DECLARE SECTION;
    char str[257];
    int zid;
    EXEC SQL END DECLARE SECTION;

    zid = string_id;
    sprintf(ofile, "%s/%s-%s.acl", zephyr_dir, atype, zclass);
    fprintf(buf, "%s~", ofile);
    out = fopen(buf, "w");
    if (out == NULL) {
	perror("opening acl file");
	exit(MR_OCONFIG);
    }

    EXEC SQL SELECT string INTO :str FROM strings WHERE string_id = :zid;
    if (sqlca.sqlcode != 0) {
	if (sqlca.sqlcode == 100) {
	    fprintf(stderr, "String %d not found for class %s type %s\n",
		    zid, zclass, atype);
	} else {
	    fprintf(stderr, "SQL error %d\n", sqlca.sqlcode);
	    exit(MR_INGRES_ERR);
	}
    }
    if (!strcmp(strtrim(str), "WILDCARD")) {
	strcpy(str, "*.*@*");
    }
    fprintf(out, "%s\n", str);
    if (fclose(out)) {
	perror("closing acl file");
	exit(MR_CCONFIG);
    }
    fix_file(ofile);
    return;
 sqlerr:
    com_err(whoami, MR_INGRES_ERR, " code %d\n", sqlca.sqlcode);
    critical_alert("DCM", "Zephyr build encountered DATABASE ERROR %d",
		   sqlca.sqlcode);
    exit(MR_INGRES_ERR);
}


getuser(user_id, zclass, atype)
int user_id;
char *zclass;
char *atype;
{
    char ofile[256], buf[256];
    FILE *out;
    EXEC SQL BEGIN DECLARE SECTION;
    char login[9];
    int zid;
    EXEC SQL END DECLARE SECTION;

    zid = user_id;
    sprintf(ofile, "%s/%s-%s.acl", zephyr_dir, atype, zclass);
    fprintf(buf, "%s~", ofile);
    out = fopen(buf, "w");
    if (out == NULL) {
	perror("opening acl file");
	exit(MR_OCONFIG);
    }

    EXEC SQL SELECT login INTO :login FROM users WHERE users_id = :zid;
    if (sqlca.sqlcode != 0) {
	if (sqlca.sqlcode == 100) {
	    fprintf(stderr, "User %d not found\n", zid);
	} else {
	    fprintf(stderr, "SQL error %d\n", sqlca.sqlcode);
	    exit(MR_INGRES_ERR);
	}
    }
    fprintf(out, "%s\n", strtrim(login));
    if (fclose(out)) {
	perror("closing acl file");
	exit(MR_CCONFIG);
    }
    fix_file(ofile);
    return;
 sqlerr:
    com_err(whoami, MR_INGRES_ERR, " code %d\n", sqlca.sqlcode);
    critical_alert("DCM", "Zephyr build encountered DATABASE ERROR %d",
		   sqlca.sqlcode);
    exit(MR_INGRES_ERR);
}


getnone(zclass, atype)
char *zclass;
char *atype;
{
    char ofile[256];

    sprintf(ofile, "%s/%s-%s.acl", zephyr_dir, atype, zclass);
    unlink(ofile);
}
