/* $Id: www.pc,v 1.8 2002-04-05 22:53:50 zacheiss Exp $
 *
 * This generates the web server user & group data.
 *
 * tom@mit.edu
 *
 * Copyright 1998 by the Massachusetts Institute of Technology.
 * For copying and distribution information, please see the file
 * <mit-copyright.h>.
 */

#include <mit-copyright.h>
#include <moira.h>
#include <moira_site.h>
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include "util.h"

EXEC SQL INCLUDE sqlca;

RCSID("$Header: /afs/athena.mit.edu/astaff/project/moiradev/repository/moira/gen/www.pc,v 1.8 2002-04-05 22:53:50 zacheiss Exp $");


#ifndef WWW_SUBDIR
#define WWW_SUBDIR "www"
#endif

#define MAX_RECSIZE 10240

char *whoami = "www.gen";
char *db = "moira/moira";

void filsys(FILE *out);
void group(FILE *out);

char www_dir[MAXPATHLEN];

char *colors[] = {"red", "green", "blue", "yellow", "mauve", "spooge",
		  "rose", "ivory", "mitbeige", "twinkie", "midnightblue",
		  "grey", "lilac", "orange", "purple", "ronhoffmanngreen"};
int ncolors = 16;


int main(int argc, char **argv)
{
  char outgrp[MAXPATHLEN];
  char outfs[MAXPATHLEN];
  char wkgrp[MAXPATHLEN];
  char wkfs[MAXPATHLEN];
  char cmd[BUFSIZ];
  FILE *outgrpf;
  FILE *outfsf;
  struct stat sb;
  char *c;

  initialize_sms_error_table();

  if (argc == 1)
    sprintf(www_dir, "%s/%s", DCM_DIR, WWW_SUBDIR);
  else
    {
      sprintf(www_dir, "%s", argv[1]);
      /* fake out dcm - we'll append .out later */
      if (c = strrchr(www_dir, '.'))
        *c = '\0';
    }

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

  if (stat(www_dir, &sb) < 0)
    {
      if (errno == ENOENT)
	{
	  if (mkdir(www_dir, 0700) < 0)
	    {
	      fprintf(stderr, "%s: unable to make directory %s (%s))\n",
		      whoami, www_dir, strerror(errno));
	      exit(MR_CCONFIG);
	    }
	}
      else
	{
	  fprintf(stderr, "%s: cannot stat %s (%s)\n", whoami, www_dir,
		  strerror(errno));
          exit(MR_CCONFIG);
	}
    }
  else if(!S_ISDIR(sb.st_mode))
    {
      fprintf(stderr, "%s: %s not a directory\n" , whoami, www_dir);
      exit(MR_CCONFIG);
    }

  EXEC SQL CONNECT :db;

  sprintf(outgrp, "%s/group", www_dir);
  sprintf(outfs, "%s/filsys", www_dir);
  sprintf(wkgrp, "%s/group~", www_dir);
  sprintf(wkfs, "%s/filsys~", www_dir);

  fprintf(stderr, "%s: building fs database...\n", whoami);
  if (!(outfsf = fopen(wkfs, "w")))
    {
      fprintf(stderr, "%s: cannot open %s for writing (%s)\n", whoami,
	      wkfs, strerror(errno));
      exit(MR_OCONFIG);
    }
  filsys(outfsf);
  if (fclose(outfsf))
    {
      fprintf(stderr, "%s: close of %s failed (%s)", whoami,
	      wkfs, strerror(errno));
      exit(MR_CCONFIG);
    }
  fix_file(outfs);

  fprintf(stderr, "%s: building group database...\n", whoami);
  if (!(outgrpf = fopen(wkgrp, "w")))
    {
      fprintf(stderr, "%s: cannot open %s for writing (%s)\n", whoami,
	      wkgrp, strerror(errno));
      exit(MR_OCONFIG);
    }
  group(outgrpf);
  if (fclose(outgrpf))
    {
      fprintf(stderr, "%s: close of %s failed (%s)", whoami, wkgrp,
	      strerror(errno));
      exit(MR_CCONFIG);
    }
  fix_file(outgrp);
  
  fprintf(stderr, "%s: building tar file...\n", whoami);
  sprintf(cmd, "(cd %s; tar cf - . ) > %s.out", www_dir, www_dir);
  if (system(cmd))
    exit(MR_TAR_FAIL);

  exit(MR_SUCCESS);
}

void filsys(FILE *out)
{
  char *c;
  EXEC SQL BEGIN DECLARE SECTION;
  char label[FILESYS_LABEL_SIZE], path[FILESYS_NAME_SIZE];
  char type[FILESYS_TYPE_SIZE], key[FSGROUP_KEY_SIZE];
  char alias[ALIAS_NAME_SIZE];
  int status, fid;
  EXEC SQL END DECLARE SECTION;

  EXEC SQL WHENEVER SQLERROR GOTO sqlerr;

  EXEC SQL DECLARE filsys_cursor CURSOR FOR
    SELECT label, name, type, filsys_id FROM filesys
    WHERE type='AFS' or type='FSGROUP'
    ORDER by label;
  EXEC SQL OPEN filsys_cursor;
  while (1)
    {
      EXEC SQL FETCH filsys_cursor INTO :label, :path, :type, :fid;
      if (sqlca.sqlcode)
 	break;

      if (!*strtrim(label))
	continue;

      if (!strcmp(strtrim(type), "FSGROUP"))
	{
	  *path = '\0';
	  EXEC SQL DECLARE group_cursor CURSOR FOR
	    SELECT f.name, g.key FROM filesys f, fsgroup g
	    WHERE f.filsys_id = g.filsys_id AND f.type='AFS'
	    AND g.group_id = :fid
	    ORDER BY g.key;
	  EXEC SQL OPEN group_cursor;
	  EXEC SQL FETCH group_cursor INTO :path, :key;
	  EXEC SQL CLOSE group_cursor;
	}

      EXEC SQL DECLARE alias_cursor CURSOR FOR
	SELECT name INTO :alias FROM alias
	WHERE type='FILESYS' AND trans=:label;

      if (!*strtrim(path))
	continue;
      for (c = label; *c; c++)
	*c = tolower(*c);
      fprintf(out, "%s:%s\n", label, path);

      EXEC SQL OPEN alias_cursor;
      while (1)
	{
	  EXEC SQL FETCH alias_cursor INTO :alias;
	  if (sqlca.sqlcode)
	    break;
	  
	  if (!*strtrim(alias))
	    continue;
	  for (c = alias; *c; c++)
	    *c = tolower(*c);
	  fprintf(out, "%s:%s\n", alias, path);
	}
      EXEC SQL CLOSE alias_cursor;
    }

  EXEC SQL CLOSE filsys_cursor;
  EXEC SQL COMMIT;

  return;

sqlerr:
  db_error(sqlca.sqlcode);
  exit(MR_DBMS_ERR);
}

void group(FILE *out)
{
  int first;
  int recsize;

  EXEC SQL BEGIN DECLARE SECTION;
  char user[USERS_LOGIN_SIZE];
  char list[LIST_NAME_SIZE];
  char parent[LIST_NAME_SIZE];
  EXEC SQL END DECLARE SECTION;

  EXEC SQL WHENEVER SQLERROR GOTO sqlerr;

  EXEC SQL DECLARE user_cursor CURSOR FOR
    SELECT login FROM users WHERE status=1 OR status=2 OR status=6 OR status=9
    ORDER by login;
  EXEC SQL OPEN user_cursor;

  while (1)
    {
      EXEC SQL FETCH user_cursor INTO :user;
      if (sqlca.sqlcode)
        break;
      strtrim(user);
      if (!isalpha(*user))
	continue;

      recsize = strlen(user) + 3;
      first = 1;
      fprintf(out, "%s:xjOhFdLKGK84w:", user);

      EXEC SQL DECLARE member_cursor CURSOR FOR
	SELECT DISTINCT l.name from list l, imembers i, users u
	WHERE u.login=:user AND u.users_id=i.member_id AND
  	i.member_type='USER' AND i.list_id=l.list_id AND
	l.grouplist != 0 and l.active != 0
	ORDER by l.name;
      EXEC SQL OPEN member_cursor;

      while (1)
	{
	  EXEC SQL FETCH member_cursor INTO :list;
	  if (sqlca.sqlcode)
	    break;
	  strtrim(list);
	  fprintf(out, "%s%s", first ? "" : ",", list);
	  recsize += strlen(list) + 1;
	  first = 0;
	  if (recsize > MAX_RECSIZE)
	    {
	      fprintf(stderr, "truncated group list for %s\n", user);
	      break;
	    }
	}

      EXEC SQL CLOSE member_cursor;
      EXEC SQL COMMIT;

      fprintf(out, "\n");
    }

  EXEC SQL CLOSE user_cursor;
  EXEC SQL COMMIT;

  return;

sqlerr:
  db_error(sqlca.sqlcode);
  exit(MR_DBMS_ERR);
}
